<commit_before>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::slice;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crate::memory::{Frame};
use crate::paging::{Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};

use crate::allocator;
use crate::device;
#[cfg(feature = "graphical_debug")]
use crate::devices::graphical_debug;
use crate::init::device_tree;
use crate::interrupt;
use crate::log::{self, info};
use crate::paging::{self, KernelMapper};

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in data.
static DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;
/// Test of zero values in thread BSS
#[thread_local]
static mut TBSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in thread data.
#[thread_local]
static mut TDATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;

pub static KERNEL_BASE: AtomicUsize = AtomicUsize::new(0);
pub static KERNEL_SIZE: AtomicUsize = AtomicUsize::new(0);
pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);

#[repr(packed)]
pub struct KernelArgs {
    kernel_base: usize,
    kernel_size: usize,
    stack_base: usize,
    stack_size: usize,
    env_base: usize,
    env_size: usize,
    dtb_base: usize,
    dtb_size: usize,
    areas_base: usize,
    areas_size: usize,

    /// The physical base 64-bit pointer to the contiguous bootstrap/initfs.
    bootstrap_base: usize,
    /// Size of contiguous bootstrap/initfs physical region, not necessarily page aligned.
    bootstrap_size: usize,
    /// Entry point the kernel will jump to.
    bootstrap_entry: usize,
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
    let bootstrap = {
        let args = &*args_ptr;

        let kernel_base = args.kernel_base as usize;
        let kernel_size = args.kernel_size as usize;
        let stack_base = args.stack_base as usize;
        let stack_size = args.stack_size as usize;
        let env_base = args.env_base as usize;
        let env_size = args.env_size as usize;
        let dtb_base = args.dtb_base as usize;
        let dtb_size = args.dtb_size as usize;

        // BSS should already be zero
        {
            assert_eq!(BSS_TEST_ZERO, 0);
            assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
        }

        KERNEL_BASE.store(kernel_base, Ordering::SeqCst);
        KERNEL_SIZE.store(kernel_size, Ordering::SeqCst);

        // Try to find serial port prior to logging
        device::serial::init_early(crate::PHYS_OFFSET + dtb_base, dtb_size);

        // Convert env to slice
        let env = slice::from_raw_parts((args.env_base + crate::PHYS_OFFSET) as *const u8, args.env_size);

        // Set up graphical debug
        #[cfg(feature = "graphical_debug")]
        graphical_debug::init(env);

        // Initialize logger
        log::init_logger(|r| {
            use core::fmt::Write;
            let _ = write!(
                crate::debug::Writer::new(),
                "{}:{} -- {}\n",
                r.target(),
                r.level(),
                r.args()
            );
        });

        info!("Redox OS starting...");
        info!("Kernel: {:X}:{:X}", args.kernel_base, args.kernel_base + args.kernel_size);
        info!("Stack: {:X}:{:X}", args.stack_base, args.stack_base + args.stack_size);
        info!("Env: {:X}:{:X}", args.env_base, args.env_base + args.env_size);
        info!("RSDPs: {:X}:{:X}", args.dtb_base, args.dtb_base + args.dtb_size);
        info!("Areas: {:X}:{:X}", args.areas_base, args.areas_base + args.areas_size);
        info!("Bootstrap: {:X}:{:X}", args.bootstrap_base, args.bootstrap_base + args.bootstrap_size);
        info!("Bootstrap entry point: {:X}", args.bootstrap_entry);

        println!("FILL MEMORY MAP START");
        device_tree::fill_memory_map(crate::PHYS_OFFSET + dtb_base, dtb_size);
        println!("FILL MEMORY MAP COMPLETE");

        println!("FILL ENV DATA START");
        let env_size = device_tree::fill_env_data(crate::PHYS_OFFSET + dtb_base, dtb_size, env_base);
        println!("FILL ENV DATA COMPLETE");

        // Initialize RMM
        println!("RMM INIT START");
        crate::arch::rmm::init(
            args.kernel_base, args.kernel_size,
            args.stack_base, args.stack_size,
            args.env_base, args.env_size,
            args.dtb_base, args.dtb_size,
            args.areas_base, args.areas_size,
            args.bootstrap_base, args.bootstrap_size,
        );
        println!("RMM INIT COMPLETE");

        // Initialize paging
        println!("PAGING INIT START");
        let tcb_offset = paging::init(0);
        println!("PAGING INIT COMPLETE");

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Reset AP variables
        CPU_COUNT.store(1, Ordering::SeqCst);
        AP_READY.store(false, Ordering::SeqCst);
        BSP_READY.store(false, Ordering::SeqCst);

        // Setup kernel heap
        println!("ALLOCATOR INIT START");
        allocator::init();
        println!("ALLOCATOR INIT COMPLETE");

        // Activate memory logging
        println!("LOG INIT START");
        log::init();
        println!("LOG INIT COMPLETE");

        // Initialize devices
        println!("DEVICE INIT START");
        device::init();
        println!("DEVICE INIT COMPLETE");

        // Initialize all of the non-core devices not otherwise needed to complete initialization
        println!("DEVICE INIT NONCORE START");
        device::init_noncore();
        println!("DEVICE INIT NONCORE COMPLETE");

        BSP_READY.store(true, Ordering::SeqCst);

        crate::Bootstrap {
            base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base)),
            page_count: args.bootstrap_size / crate::memory::PAGE_SIZE,
            entry: args.bootstrap_entry,
            env,
        }
    };

    println!("KMAIN");
    crate::kmain(CPU_COUNT.load(Ordering::SeqCst), bootstrap);
}

#[repr(packed)]
pub struct KernelArgsAp {
    cpu_id: u64,
    page_table: u64,
    stack_start: u64,
    stack_end: u64,
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
    loop{}
}

#[naked]
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, _singlestep: usize) -> ! {
    core::arch::asm!(
        "
        udf #0
        ",
        options(noreturn)
    );
    /*TODO: update to asm
    let cpu_id: usize = 0;
    let spsr: u32 = 0;

    llvm_asm!("msr   spsr_el1, $0" : : "r"(spsr) : : "volatile");
    llvm_asm!("msr   elr_el1, $0" : : "r"(ip) : : "volatile");
    llvm_asm!("msr   sp_el0, $0" : : "r"(sp) : : "volatile");

    llvm_asm!("mov   x0, $0" : : "r"(arg) : : "volatile");
    llvm_asm!("eret" : : : : "volatile");

    unreachable!();
    */
}
<commit_msg>Get aarch64 kernel to boot to the point of needing context switch<commit_after>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::slice;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crate::memory::{Frame};
use crate::paging::{Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};

use crate::allocator;
use crate::device;
#[cfg(feature = "graphical_debug")]
use crate::devices::graphical_debug;
use crate::init::device_tree;
use crate::interrupt;
use crate::log::{self, info};
use crate::paging::{self, KernelMapper};

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in data.
static DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;
/// Test of zero values in thread BSS
#[thread_local]
static mut TBSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in thread data.
#[thread_local]
static mut TDATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;

pub static KERNEL_BASE: AtomicUsize = AtomicUsize::new(0);
pub static KERNEL_SIZE: AtomicUsize = AtomicUsize::new(0);
pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);

#[repr(packed)]
pub struct KernelArgs {
    kernel_base: usize,
    kernel_size: usize,
    stack_base: usize,
    stack_size: usize,
    env_base: usize,
    env_size: usize,
    dtb_base: usize,
    dtb_size: usize,
    areas_base: usize,
    areas_size: usize,

    /// The physical base 64-bit pointer to the contiguous bootstrap/initfs.
    bootstrap_base: usize,
    /// Size of contiguous bootstrap/initfs physical region, not necessarily page aligned.
    bootstrap_size: usize,
    /// Entry point the kernel will jump to.
    bootstrap_entry: usize,
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
    let bootstrap = {
        let args = &*args_ptr;

        let kernel_base = args.kernel_base as usize;
        let kernel_size = args.kernel_size as usize;
        let stack_base = args.stack_base as usize;
        let stack_size = args.stack_size as usize;
        let env_base = args.env_base as usize;
        let env_size = args.env_size as usize;
        let dtb_base = args.dtb_base as usize;
        let dtb_size = args.dtb_size as usize;

        // BSS should already be zero
        {
            assert_eq!(BSS_TEST_ZERO, 0);
            assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
        }

        KERNEL_BASE.store(kernel_base, Ordering::SeqCst);
        KERNEL_SIZE.store(kernel_size, Ordering::SeqCst);

        //TODO: Remove hard-coded UART for QEMU virt machine
        {
            let mut serial_port = crate::device::uart_pl011::SerialPort::new(
                crate::PHYS_OFFSET + 0x9000000
            );
            serial_port.init(false);
            serial_port.write(b"UART\n");
            *crate::device::serial::COM1.lock() = Some(serial_port);
        }

        // Try to find serial port prior to logging
        device::serial::init_early(crate::PHYS_OFFSET + dtb_base, dtb_size);

        // Convert env to slice
        let env = slice::from_raw_parts((args.env_base + crate::PHYS_OFFSET) as *const u8, args.env_size);

        // Set up graphical debug
        #[cfg(feature = "graphical_debug")]
        graphical_debug::init(env);

        // Initialize logger
        log::init_logger(|r| {
            use core::fmt::Write;
            let _ = write!(
                crate::debug::Writer::new(),
                "{}:{} -- {}\n",
                r.target(),
                r.level(),
                r.args()
            );
        });

        info!("Redox OS starting...");
        info!("Kernel: {:X}:{:X}", args.kernel_base, args.kernel_base + args.kernel_size);
        info!("Stack: {:X}:{:X}", args.stack_base, args.stack_base + args.stack_size);
        info!("Env: {:X}:{:X}", args.env_base, args.env_base + args.env_size);
        info!("RSDPs: {:X}:{:X}", args.dtb_base, args.dtb_base + args.dtb_size);
        info!("Areas: {:X}:{:X}", args.areas_base, args.areas_base + args.areas_size);
        info!("Bootstrap: {:X}:{:X}", args.bootstrap_base, args.bootstrap_base + args.bootstrap_size);
        info!("Bootstrap entry point: {:X}", args.bootstrap_entry);

        /* NOT USED WITH UEFI
        device_tree::fill_memory_map(crate::PHYS_OFFSET + dtb_base, dtb_size);

        let env_size = device_tree::fill_env_data(crate::PHYS_OFFSET + dtb_base, dtb_size, env_base);
        */

        // Initialize RMM
        crate::arch::rmm::init(
            args.kernel_base, args.kernel_size,
            args.stack_base, args.stack_size,
            args.env_base, args.env_size,
            args.dtb_base, args.dtb_size,
            args.areas_base, args.areas_size,
            args.bootstrap_base, args.bootstrap_size,
        );

        // Initialize paging
        let tcb_offset = paging::init(0);

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Reset AP variables
        CPU_COUNT.store(1, Ordering::SeqCst);
        AP_READY.store(false, Ordering::SeqCst);
        BSP_READY.store(false, Ordering::SeqCst);

        // Setup kernel heap
        allocator::init();

        // Activate memory logging
        log::init();

        // Initialize devices
        device::init();

        // Initialize all of the non-core devices not otherwise needed to complete initialization
        device::init_noncore();

        BSP_READY.store(true, Ordering::SeqCst);

        crate::Bootstrap {
            base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base)),
            page_count: args.bootstrap_size / crate::memory::PAGE_SIZE,
            entry: args.bootstrap_entry,
            env,
        }
    };

    crate::kmain(CPU_COUNT.load(Ordering::SeqCst), bootstrap);
}

#[repr(packed)]
pub struct KernelArgsAp {
    cpu_id: u64,
    page_table: u64,
    stack_start: u64,
    stack_end: u64,
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
    loop{}
}

#[naked]
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, _singlestep: usize) -> ! {
    core::arch::asm!(
        "
        udf #0
        ",
        options(noreturn)
    );
    /*TODO: update to asm
    let cpu_id: usize = 0;
    let spsr: u32 = 0;

    llvm_asm!("msr   spsr_el1, $0" : : "r"(spsr) : : "volatile");
    llvm_asm!("msr   elr_el1, $0" : : "r"(ip) : : "volatile");
    llvm_asm!("msr   sp_el0, $0" : : "r"(sp) : : "volatile");

    llvm_asm!("mov   x0, $0" : : "r"(arg) : : "volatile");
    llvm_asm!("eret" : : : : "volatile");

    unreachable!();
    */
}
<|endoftext|>


<commit_before>use libc::*;
use std::mem;
use std::collections::VecDeque;
// I tried
// It's a bit hard to write this without a Windows pc on hand...
// But this should work on Windows Vista, 7, and 8
#[link(name = "XINPUT9_1_0")]
extern "stdcall" {
	fn XInputGetCapabilities(index: u32, flags: u32, capabilities: *mut Capabilities) -> i32;
	fn XInputGetState(index: u32, state: *mut State) -> i32;
}

#[repr(C)]
struct State {
	packet: i32,
	gamepad: Gamepad
}

#[repr(C)]
struct Capabilities {
	_type: u8,
	sub_type: u8,
	flags: u32,
	gamepad: Gamepad,
	vibration: Vibration
}

bitflags!(
	flags Buttons: u32 {
		const DPAD_UP = 0x0001,
		const DPAD_DOWN = 0x0002,
		const DPAD_LEFT = 0x0004,
		const DPAD_RIGHT = 0x0008,
		const START = 0x0010,
		const BACK = 0x0020,
		const LEFT_THUMB = 0x0040,
		const RIGHT_THUMB = 0x0080,
		const LEFT_SHOULDER = 0x0100,
		const RIGHT_SHOULDER = 0x0200,
		const A = 0x1000,
		const B = 0x2000,
		const X = 0x4000,
		const Y = 0x8000,
	}
);
#[repr(C)]
#[derive(Copy)]
struct Gamepad {
	buttons: Buttons,
	left_trigger: u8,
	right_trigger: u8,
	thumb_lx: i16,
	thumb_ly: i16,
	thumb_rx: i16,
	thumb_ry: i16
}
#[repr(C)]
struct Vibration {
	left_motor_speed: i32,
	right_motor_speed: i32
}

/// Scan for joysticks
pub fn scan() -> Vec<Joystick> {
	(0..4).filter_map(|i| Joystick::new(i).ok()).collect()
}

pub struct NativeJoystick {
	index: u8,
	last: Gamepad,
	last_packet: i32,
	events: VecDeque<::Event>
}
impl ::Joystick for NativeJoystick {
	type WithState = NativeJoystick;
	fn new(index: u8) -> Result<NativeJoystick, &'static str> {
		unsafe {
			let mut caps: Capabilities = mem::uninitialized();
			match XInputGetCapabilities(index as u32, 0, &mut caps) {
				0 =>
					Ok(NativeJoystick {
						index: index,
						last: caps.gamepad,
						last_packet: 0,
						events: VecDeque::with_capacity(10)
					}),
				0x48F => Err("Device not connected"),
				_ => Err("Unknown Error")
			}
		}
	}
	fn poll(&mut self) -> Option<::Event> {
		use ::StatefulJoystick;
		self.update();
		self.events.pop_back()
	}
	fn is_connected(&self) -> bool {
		true
	}
	fn get_id(&self) -> String {
		String::from_str("XInput Device")
	}
	fn get_index(&self) -> u8 {
		self.index
	}
	fn get_num_buttons(&self) -> u8 {
		4
	}
	fn get_num_axes(&self) -> u8 {
		4
	}
	fn with_state(self) -> NativeJoystick {
		self
	}
}
macro_rules! event{
	(button $this:expr, $now:expr, $last:expr, $btn:expr, $id:expr) => (
		{
			let now_btn = $now.buttons.contains($btn);
			let last_btn = $last.buttons.contains($btn);
			if now_btn && !last_btn {
				$this.events.push_back(::Event::ButtonPressed($id))
			} else if !now_btn && last_btn {
				$this.events.push_back(::Event::ButtonReleased($id))
			}
		}
	);
	(axis $this:expr, $now:expr, $last:expr, $field:ident, $id:expr) => (
		if $now.$field != $last.$field {
			$this.events.push_back(::Event::JoystickMoved($id, $now.$field))
		}
	);
	(axes $this:expr, $now:expr, $last:expr, $($field:ident => $id:expr),+) => ({
		$(event!(axis $this, $now, $last, $field, $id);)+
	});
	(buttons $this:expr, $now:expr, $last:expr, $($btn:ident => $id:expr),+) => ({
		$(event!(button $this, $now, $last, $btn, $id);)+
	});
}
impl ::StatefulJoystick for NativeJoystick {
	fn get_axis(&self, index: u8) -> Option<i16> {
		match index {
			0 => Some(self.last.thumb_lx),
			1 => Some(self.last.thumb_ly),
			2 => Some(self.last.thumb_rx),
			3 => Some(self.last.thumb_ry),
			_ => None
		}
	}
	fn get_button(&self, index: u8) -> Option<bool> {
		let bits = match index {
			1 => Some(A),
			2 => Some(B),
			3 => Some(X),
			0 => Some(Y),
			_ => None
		};
		bits.map(|v| self.last.buttons.contains(v))
	}
	fn update(&mut self) {
		let state = unsafe {
			let mut state: State = mem::uninitialized();
			XInputGetState(self.index as u32, &mut state);
			state
		};
		let now = state.gamepad;
		if state.packet != self.last_packet {
			let last = self.last;
			event!{axes self, now, last,
				thumb_lx => 0,
				thumb_ly => 1,
				thumb_rx => 2,
				thumb_ry => 3
			}
			event!{buttons self, now, last,
				A => 1,
				B => 2,
				X => 3,
				Y => 0
			}
		}
		self.last_packet = state.packet;
		self.last = now;
	}
}
<commit_msg>Map more buttons on windows<commit_after>use libc::*;
use std::mem;
use std::collections::VecDeque;
// I tried
// It's a bit hard to write this without a Windows pc on hand...
// But this should work on Windows Vista, 7, and 8
#[link(name = "XINPUT9_1_0")]
extern "stdcall" {
	fn XInputGetCapabilities(index: u32, flags: u32, capabilities: *mut Capabilities) -> i32;
	fn XInputGetState(index: u32, state: *mut State) -> i32;
}

#[repr(C)]
struct State {
	packet: i32,
	gamepad: Gamepad
}

#[repr(C)]
struct Capabilities {
	_type: u8,
	sub_type: u8,
	flags: u32,
	gamepad: Gamepad,
	vibration: Vibration
}

bitflags!(
	flags Buttons: u32 {
		const DPAD_UP = 0x0001,
		const DPAD_DOWN = 0x0002,
		const DPAD_LEFT = 0x0004,
		const DPAD_RIGHT = 0x0008,
		const START = 0x0010,
		const BACK = 0x0020,
		const LEFT_THUMB = 0x0040,
		const RIGHT_THUMB = 0x0080,
		const LEFT_SHOULDER = 0x0100,
		const RIGHT_SHOULDER = 0x0200,
		const A = 0x1000,
		const B = 0x2000,
		const X = 0x4000,
		const Y = 0x8000,
	}
);
#[repr(C)]
#[derive(Copy)]
struct Gamepad {
	buttons: Buttons,
	left_trigger: u8,
	right_trigger: u8,
	thumb_lx: i16,
	thumb_ly: i16,
	thumb_rx: i16,
	thumb_ry: i16
}
#[repr(C)]
struct Vibration {
	left_motor_speed: i32,
	right_motor_speed: i32
}

/// Scan for joysticks
pub fn scan() -> Vec<Joystick> {
	(0..4).filter_map(|i| Joystick::new(i).ok()).collect()
}

pub struct NativeJoystick {
	index: u8,
	last: Gamepad,
	last_packet: i32,
	events: VecDeque<::Event>
}
impl ::Joystick for NativeJoystick {
	type WithState = NativeJoystick;
	fn new(index: u8) -> Result<NativeJoystick, &'static str> {
		unsafe {
			let mut caps: Capabilities = mem::uninitialized();
			match XInputGetCapabilities(index as u32, 0, &mut caps) {
				0 =>
					Ok(NativeJoystick {
						index: index,
						last: caps.gamepad,
						last_packet: 0,
						events: VecDeque::with_capacity(10)
					}),
				0x48F => Err("Device not connected"),
				_ => Err("Unknown Error")
			}
		}
	}
	fn poll(&mut self) -> Option<::Event> {
		use ::StatefulJoystick;
		self.update();
		self.events.pop_back()
	}
	fn is_connected(&self) -> bool {
		true
	}
	fn get_id(&self) -> String {
		String::from_str("XInput Device")
	}
	fn get_index(&self) -> u8 {
		self.index
	}
	fn get_num_buttons(&self) -> u8 {
		4
	}
	fn get_num_axes(&self) -> u8 {
		4
	}
	fn with_state(self) -> NativeJoystick {
		self
	}
}
macro_rules! event{
	(button $this:expr, $now:expr, $last:expr, $btn:expr, $id:expr) => (
		{
			let now_btn = $now.buttons.contains($btn);
			let last_btn = $last.buttons.contains($btn);
			if now_btn && !last_btn {
				$this.events.push_back(::Event::ButtonPressed($id))
			} else if !now_btn && last_btn {
				$this.events.push_back(::Event::ButtonReleased($id))
			}
		}
	);
	(axis $this:expr, $now:expr, $last:expr, $field:ident, $id:expr) => (
		if $now.$field != $last.$field {
			$this.events.push_back(::Event::JoystickMoved($id, $now.$field))
		}
	);
	(axes $this:expr, $now:expr, $last:expr, $($field:ident => $id:expr),+) => ({
		$(event!(axis $this, $now, $last, $field, $id);)+
	});
	(buttons $this:expr, $now:expr, $last:expr, $($btn:ident => $id:expr),+) => ({
		$(event!(button $this, $now, $last, $btn, $id);)+
	});
}
impl ::StatefulJoystick for NativeJoystick {
	fn get_axis(&self, index: u8) -> Option<i16> {
		match index {
			0 => Some(self.last.thumb_lx),
			1 => Some(self.last.thumb_ly),
			2 => Some(self.last.thumb_rx),
			3 => Some(self.last.thumb_ry),
			_ => None
		}
	}
	fn get_button(&self, index: u8) -> Option<bool> {
		let bits = match index {
		0 => Some(Y),
			1 => Some(A),
			2 => Some(B),
			3 => Some(X),
			4 => Some(LEFT_SHOULDER),
			5 => Some(RIGHT_SHOULDER),
			8 => Some(BACK),
			9 => Some(START),
			10 => Some(LEFT_TRIGGER),
			11 => Some(RIGHT_TRIGGER),
			_ => None
		};
		bits.map(|v| self.last.buttons.contains(v))
	}
	fn update(&mut self) {
		let state = unsafe {
			let mut state: State = mem::uninitialized();
			XInputGetState(self.index as u32, &mut state);
			state
		};
		let now = state.gamepad;
		if state.packet != self.last_packet {
			let last = self.last;
			event!{axes self, now, last,
				thumb_lx => 0,
				thumb_ly => 1,
				thumb_rx => 2,
				thumb_ry => 3
			}
			event!{buttons self, now, last,
			Y => 0,
				A => 1,
				B => 2,
				X => 3,
				LEFT_SHOULDER => 4,
				RIGHT_SHOULDER => 5,
				BACK => 8,
				START => 9,
				LEFT_TRIGGER => 10,
				RIGHT_TRIGGER => 11
			}
		}
		self.last_packet = state.packet;
		self.last = now;
	}
}
<|endoftext|>


<commit_before>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;
use glutin::{PossiblyCurrent as Pc, ContextCurrentState};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new<T: ContextCurrentState, E>(
        wb: glutin::window::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::event_loop::EventLoop<E>,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window<T: ContextCurrentState>(gl_window: glutin::WindowedContext<T>) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked<T: ContextCurrentState>(gl_window: glutin::WindowedContext<T>) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug<T: ContextCurrentState>(gl_window: glutin::WindowedContext<T>, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = unsafe {
            gl_window.treat_as_current()
        };
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = unsafe { context::Context::new(glutin_backend, checked, debug) }?;
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild<T: ContextCurrentState>(
        &self,
        wb: glutin::window::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::event_loop::EventLoop<()>,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe {
            new_gl_window.treat_as_current()
        };

        // Replace the stored WindowedContext with the new one.
        {
            let mut gl_window = self.gl_window.borrow_mut();
            Takeable::insert(&mut gl_window, new_gl_window);
        }

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        unsafe { self.context.rebuild(backend) }?;

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            DisplayCreationError::GlutinCreationError(err) => write!(fmt, "{}", err),
            DisplayCreationError::IncompatibleOpenGl(err) => write!(fmt, "{}", err),
        }
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("I/O Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::OsError(e)) => panic!("OS Error while swapping buffers: {:?}", e),
            // As of writing the FunctionUnavailable error is only thrown if
            // you are swapping buffers with damage rectangles specified.
            // Currently we don't support this so we just panic as this
            // case should be unreachable.
            Err(glutin::ContextError::FunctionUnavailable) => panic!("function unavailable error while swapping buffers"),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.inner_size()
            .into();
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<commit_msg>implement Debug trait for Display<commit_after>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use backend;
use backend::Backend;
use backend::Context;
use context;
use debug;
use glutin::{ContextCurrentState, PossiblyCurrent as Pc};
use std::cell::{Cell, Ref, RefCell};
use std::error::Error;
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_void;
use std::rc::Rc;
use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl std::fmt::Debug for Display {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "[glium::backend::glutin::Display]")
    }
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new<T: ContextCurrentState, E>(
        wb: glutin::window::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::event_loop::EventLoop<E>,
    ) -> Result<Self, DisplayCreationError> {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
    ) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
    ) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl> {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl> {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl> {
        let gl_window = unsafe { gl_window.treat_as_current() };
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = unsafe { context::Context::new(glutin_backend, checked, debug) }?;
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild<T: ContextCurrentState>(
        &self,
        wb: glutin::window::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::event_loop::EventLoop<()>,
    ) -> Result<(), DisplayCreationError> {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe { new_gl_window.treat_as_current() };

        // Replace the stored WindowedContext with the new one.
        {
            let mut gl_window = self.gl_window.borrow_mut();
            Takeable::insert(&mut gl_window, new_gl_window);
        }

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        unsafe { self.context.rebuild(backend) }?;

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            DisplayCreationError::GlutinCreationError(err) => write!(fmt, "{}", err),
            DisplayCreationError::IncompatibleOpenGl(err) => write!(fmt, "{}", err),
        }
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => {
                panic!("I/O Error while swapping buffers: {:?}", e)
            }
            Err(glutin::ContextError::OsError(e)) => {
                panic!("OS Error while swapping buffers: {:?}", e)
            }
            // As of writing the FunctionUnavailable error is only thrown if
            // you are swapping buffers with damage rectangles specified.
            // Currently we don't support this so we just panic as this
            // case should be unreachable.
            Err(glutin::ContextError::FunctionUnavailable) => {
                panic!("function unavailable error while swapping buffers")
            }
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.inner_size().into();
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<|endoftext|>


<commit_before>//! Manages tree-sitter's configuration file.

use anyhow::{anyhow, Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::PathBuf;
use std::{env, fs};

/// Holds the contents of tree-sitter's configuration file.
///
/// The file typically lives at `~/.config/tree-sitter/config.json`, but see the [`load`][] method
/// for the full details on where it might be located.
///
/// This type holds the generic JSON content of the configuration file.  Individual tree-sitter
/// components will use the [`get`][] method to parse that JSON to extract configuration fields
/// that are specific to that component.
#[derive(Debug)]
pub struct Config {
    pub location: PathBuf,
    pub config: Value,
}

impl Config {
    pub fn find_config_file() -> Result<Option<PathBuf>> {
        if let Ok(path) = env::var("TREE_SITTER_DIR") {
            let mut path = PathBuf::from(path);
            path.push("config.json");
            if path.is_file() {
                return Ok(Some(path));
            }
        }

        let xdg_path = Self::xdg_config_file()?;
        if xdg_path.is_file() {
            return Ok(Some(xdg_path));
        }

        let legacy_path = dirs::home_dir()
            .ok_or(anyhow!("Cannot determine home directory"))?
            .join(".tree-sitter/config.json");
        if legacy_path.is_file() {
            return Ok(Some(legacy_path));
        }

        Ok(None)
    }

    fn xdg_config_file() -> Result<PathBuf> {
        let xdg_path = dirs::config_dir()
            .ok_or(anyhow!("Cannot determine config directory"))?
            .join("tree-sitter/config.json");
        Ok(xdg_path)
    }

    /// Locates and loads in the user's configuration file.  We search for the configuration file
    /// in the following locations, in order:
    ///
    ///   - `$TREE_SITTER_DIR/config.json`, if the `TREE_SITTER_DIR` environment variable is set
    ///   - `tree-sitter/config.json` in your default user configuration directory, as determined
    ///     by [`dirs::config_dir`](https://docs.rs/dirs/*/dirs/fn.config_dir.html)
    ///   - `$HOME/.tree-sitter/config.json` as a fallback from where tree-sitter _used_ to store
    ///     its configuration
    pub fn load() -> Result<Config> {
        let location = match Self::find_config_file()? {
            Some(location) => location,
            None => return Config::initial(),
        };
        let content = fs::read_to_string(&location)
            .with_context(|| format!("Failed to read {}", &location.to_string_lossy()))?;
        let config = serde_json::from_str(&content)
            .with_context(|| format!("Bad JSON config {}", &location.to_string_lossy()))?;
        Ok(Config { location, config })
    }

    /// Creates an empty initial configuration file.  You can then use the [`add`][] method to add
    /// the component-specific configuration types for any components that want to add content to
    /// the default file, and then use [`save`][] to write the configuration to disk.
    ///
    /// (Note that this is typically only done by the `tree-sitter init-config` command.)
    pub fn initial() -> Result<Config> {
        let location = Self::xdg_config_file()?;
        let config = serde_json::json!({});
        Ok(Config { location, config })
    }

    /// Saves this configuration to the file that it was originally loaded from.
    pub fn save(&self) -> Result<()> {
        let json = serde_json::to_string_pretty(&self.config)?;
        fs::create_dir_all(self.location.parent().unwrap())?;
        fs::write(&self.location, json)?;
        Ok(())
    }

    /// Parses a component-specific configuration from the configuration file.  The type `C` must
    /// be [deserializable](https://docs.rs/serde/*/serde/trait.Deserialize.html) from a JSON
    /// object, and must only include the fields relevant to that component.
    pub fn get<C>(&self) -> Result<C>
    where
        C: for<'de> Deserialize<'de>,
    {
        let config = serde_json::from_value(self.config.clone())?;
        Ok(config)
    }

    /// Adds a component-specific configuration to the configuration file.  The type `C` must be
    /// [serializable](https://docs.rs/serde/*/serde/trait.Serialize.html) into a JSON object, and
    /// must only include the fields relevant to that component.
    pub fn add<C>(&mut self, config: C) -> Result<()>
    where
        C: Serialize,
    {
        let mut config = serde_json::to_value(&config)?;
        self.config
            .as_object_mut()
            .unwrap()
            .append(config.as_object_mut().unwrap());
        Ok(())
    }
}
<commit_msg>cli: fix warnings from `cargo doc`<commit_after>//! Manages tree-sitter's configuration file.

use anyhow::{anyhow, Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::PathBuf;
use std::{env, fs};

/// Holds the contents of tree-sitter's configuration file.
///
/// The file typically lives at `~/.config/tree-sitter/config.json`, but see the [`Config::load`][]
/// method for the full details on where it might be located.
///
/// This type holds the generic JSON content of the configuration file.  Individual tree-sitter
/// components will use the [`Config::get`][] method to parse that JSON to extract configuration
/// fields that are specific to that component.
#[derive(Debug)]
pub struct Config {
    pub location: PathBuf,
    pub config: Value,
}

impl Config {
    pub fn find_config_file() -> Result<Option<PathBuf>> {
        if let Ok(path) = env::var("TREE_SITTER_DIR") {
            let mut path = PathBuf::from(path);
            path.push("config.json");
            if path.is_file() {
                return Ok(Some(path));
            }
        }

        let xdg_path = Self::xdg_config_file()?;
        if xdg_path.is_file() {
            return Ok(Some(xdg_path));
        }

        let legacy_path = dirs::home_dir()
            .ok_or(anyhow!("Cannot determine home directory"))?
            .join(".tree-sitter/config.json");
        if legacy_path.is_file() {
            return Ok(Some(legacy_path));
        }

        Ok(None)
    }

    fn xdg_config_file() -> Result<PathBuf> {
        let xdg_path = dirs::config_dir()
            .ok_or(anyhow!("Cannot determine config directory"))?
            .join("tree-sitter/config.json");
        Ok(xdg_path)
    }

    /// Locates and loads in the user's configuration file.  We search for the configuration file
    /// in the following locations, in order:
    ///
    ///   - `$TREE_SITTER_DIR/config.json`, if the `TREE_SITTER_DIR` environment variable is set
    ///   - `tree-sitter/config.json` in your default user configuration directory, as determined
    ///     by [`dirs::config_dir`](https://docs.rs/dirs/*/dirs/fn.config_dir.html)
    ///   - `$HOME/.tree-sitter/config.json` as a fallback from where tree-sitter _used_ to store
    ///     its configuration
    pub fn load() -> Result<Config> {
        let location = match Self::find_config_file()? {
            Some(location) => location,
            None => return Config::initial(),
        };
        let content = fs::read_to_string(&location)
            .with_context(|| format!("Failed to read {}", &location.to_string_lossy()))?;
        let config = serde_json::from_str(&content)
            .with_context(|| format!("Bad JSON config {}", &location.to_string_lossy()))?;
        Ok(Config { location, config })
    }

    /// Creates an empty initial configuration file.  You can then use the [`Config::add`][] method
    /// to add the component-specific configuration types for any components that want to add
    /// content to the default file, and then use [`Config::save`][] to write the configuration to
    /// disk.
    ///
    /// (Note that this is typically only done by the `tree-sitter init-config` command.)
    pub fn initial() -> Result<Config> {
        let location = Self::xdg_config_file()?;
        let config = serde_json::json!({});
        Ok(Config { location, config })
    }

    /// Saves this configuration to the file that it was originally loaded from.
    pub fn save(&self) -> Result<()> {
        let json = serde_json::to_string_pretty(&self.config)?;
        fs::create_dir_all(self.location.parent().unwrap())?;
        fs::write(&self.location, json)?;
        Ok(())
    }

    /// Parses a component-specific configuration from the configuration file.  The type `C` must
    /// be [deserializable](https://docs.rs/serde/*/serde/trait.Deserialize.html) from a JSON
    /// object, and must only include the fields relevant to that component.
    pub fn get<C>(&self) -> Result<C>
    where
        C: for<'de> Deserialize<'de>,
    {
        let config = serde_json::from_value(self.config.clone())?;
        Ok(config)
    }

    /// Adds a component-specific configuration to the configuration file.  The type `C` must be
    /// [serializable](https://docs.rs/serde/*/serde/trait.Serialize.html) into a JSON object, and
    /// must only include the fields relevant to that component.
    pub fn add<C>(&mut self, config: C) -> Result<()>
    where
        C: Serialize,
    {
        let mut config = serde_json::to_value(&config)?;
        self.config
            .as_object_mut()
            .unwrap()
            .append(config.as_object_mut().unwrap());
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

pub struct DeleteHook {
    storepath: PathBuf,

    runtime: GRuntime,

    position: HookPosition,
}

impl DeleteHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
        DeleteHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
            position: p,
        }
    }

}

impl Debug for DeleteHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "DeleteHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl Hook for DeleteHook {

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

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for DeleteHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for DeleteHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT DELETE HOOK]: {:?}", id);
        Ok(())
    }

}

<commit_msg>Add implementation for delete hook<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;

use libimagerror::trace::trace_error;
use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagutil::debug_result::*;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

pub struct DeleteHook {
    storepath: PathBuf,

    runtime: GRuntime,

    position: HookPosition,
}

impl DeleteHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
        DeleteHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
            position: p,
        }
    }

}

impl Debug for DeleteHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "DeleteHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl Hook for DeleteHook {

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

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for DeleteHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for DeleteHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        use vcs::git::action::StoreAction;
        use vcs::git::config::commit_message;
        use vcs::git::error::MapIntoHookError;
        use vcs::git::util::fetch_index;
        use git2::{ADD_DEFAULT, STATUS_WT_DELETED, IndexMatchedPath};

        debug!("[GIT DELETE HOOK]: {:?}", id);

        let action    = StoreAction::Delete;
        let cfg       = try!(self.runtime.config_value_or_err(&action));
        let repo      = try!(self.runtime.repository(&action));
        let mut index = try!(fetch_index(repo, &action));

        let signature = try!(
            repo.signature()
                .map_err_into(GHEK::MkSignature)
                .map_dbg_err_str("Failed to fetch signature")
                .map_into_hook_error()
        );

        let head = try!(
            repo.head()
                .map_err_into(GHEK::HeadFetchError)
                .map_dbg_err_str("Failed to fetch HEAD")
                .map_into_hook_error()
        );

        let file_status = try!(
            repo
                .status_file(id.local())
                .map_dbg_err_str("Failed to fetch file status")
                .map_dbg_err(|e| format!("\t->  {:?}", e))
                .map_err_into(GHEK::RepositoryFileStatusError)
                .map_into_hook_error()
        );

        let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
            debug!("[GIT DELETE HOOK]: Checking file status for: {}", path.display());
            if file_status.contains(STATUS_WT_DELETED) {
                debug!("[GIT DELETE HOOK]: File is deleted: {}", path.display());
                0
            } else {
                debug!("[GIT DELETE HOOK]: Ignoring file: {}", path.display());
                1
            }
        };

        try!(
            index.add_all(&[id.local()], ADD_DEFAULT, Some(cb as &mut IndexMatchedPath))
                .map_err_into(GHEK::RepositoryPathAddingError)
                .map_dbg_err_str("Failed to add to index")
                .map_into_hook_error()
        );

        let tree_id = try!(
            index.write_tree()
                .map_err_into(GHEK::RepositoryIndexWritingError)
                .map_dbg_err_str("Failed to write tree")
                .map_into_hook_error()
        );

        let mut parents = Vec::new();
        {
            let commit = try!(
                repo.find_commit(head.target().unwrap())
                    .map_err_into(GHEK::RepositoryParentFetchingError)
                    .map_dbg_err_str("Failed to find commit HEAD")
                    .map_into_hook_error()
            );
            parents.push(commit);
        }

        // for converting from Vec<Commit> to Vec<&Commit>
        let parents = parents.iter().collect::<Vec<_>>();

        let tree = try!(
            repo.find_tree(tree_id)
                .map_err_into(GHEK::RepositoryParentFetchingError)
                .map_dbg_err_str("Failed to find tree")
                .map_into_hook_error()
        );

        let message = try!(commit_message(&repo, cfg, action)
                .map_dbg_err_str("Failed to get commit message"));

        try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
            .map_dbg_str("Committed")
            .map_dbg_err_str("Failed to commit")
            .map_err_into(GHEK::RepositoryCommittingError)
            .map_into_hook_error()
        );

        index.write()
            .map_err_into(GHEK::RepositoryIndexWritingError)
            .map_dbg_err_str("Failed to write tree")
            .map_into_hook_error()
            .map(|_| ())
    }

}

<|endoftext|>


<commit_before>// Copyright 2016 The Cartographer Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use cgmath::{Angle, Decomposed, Deg, InnerSpace, Matrix4, One, Quaternion, Rad, Rotation,
             Rotation3, Transform, Vector3, Zero};
use opengl;
use std::f32;

// Constructs a projection matrix. Math lifted from ThreeJS.
fn make_projection_matrix<A: Into<Rad<f32>>>(
    near: f32,
    far: f32,
    fov: A,
    zoom: f32,
    aspect_ratio: f32,
) -> Matrix4<f32> {
    let top = 0.5 * near * fov.into().tan() / zoom;
    let height = 2. * top;
    let width = aspect_ratio * height;
    let left = -0.5 * width;

    let right = left + width;
    let bottom = top - height;

    // Matrix is column major.
    let x = 2. * near / (right - left);
    let y = 2. * near / (top - bottom);

    let a = (right + left) / (right - left);
    let b = (top + bottom) / (top - bottom);
    let c = -(far + near) / (far - near);
    let d = -2. * far * near / (far - near);

    Matrix4::new(
        x,
        0.,
        0.,
        0., // Column 0
        0.,
        y,
        0.,
        0., // Column 1
        a,
        b,
        c,
        -1., // Column 2
        0.,
        0.,
        d,
        0., // Column 3
    )
}

#[derive(Debug)]
pub struct Camera {
    pub moving_backward: bool,
    pub moving_forward: bool,
    pub moving_left: bool,
    pub moving_right: bool,
    pub moving_down: bool,
    pub moving_up: bool,
    pub width: i32,
    pub height: i32,

    movement_speed: f32,
    theta: Rad<f32>,
    phi: Rad<f32>,

    moved: bool,
    transform: Decomposed<Vector3<f32>, Quaternion<f32>>,

    projection_matrix: Matrix4<f32>,
}

impl Camera {
    pub fn new(gl: &opengl::Gl, width: i32, height: i32) -> Self {
        let mut camera = Camera {
            movement_speed: 1.5,
            moving_backward: false,
            moving_forward: false,
            moving_left: false,
            moving_right: false,
            moving_down: false,
            moving_up: false,
            moved: true,
            theta: Rad(0.),
            phi: Rad(0.),
            transform: Decomposed {
                scale: 1.,
                rot: Quaternion::one(),
                disp: Vector3::new(0., 0., 150.),
            },

            // These will be set by set_size().
            projection_matrix: One::one(),
            width: 0,
            height: 0,
        };
        camera.set_size(gl, width, height);
        camera
    }

    pub fn set_size(&mut self, gl: &opengl::Gl, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.projection_matrix =
            make_projection_matrix(0.1, 10000., Deg(45.), 1., width as f32 / height as f32);
        unsafe {
            gl.Viewport(0, 0, width, height);
        }
    }

    pub fn get_world_to_gl(&self) -> Matrix4<f32> {
        let world_to_camera: Matrix4<f32> = self.transform.inverse_transform().unwrap().into();
        self.projection_matrix * world_to_camera
    }

    /// Update the camera position for the current frame. Returns true if the camera moved in this
    /// step.
    pub fn update(&mut self) -> bool {
        let mut moved = self.moved;
        self.moved = false;

        let mut pan = Vector3::zero();
        if self.moving_right {
            pan.x += 1.;
        }
        if self.moving_left {
            pan.x -= 1.;
        }
        if self.moving_backward {
            pan.z += 1.;
        }
        if self.moving_forward {
            pan.z -= 1.;
        }
        if self.moving_up {
            pan.y += 1.;
        }
        if self.moving_down {
            pan.y -= 1.;
        }

        if pan.magnitude2() > 0. {
            moved = true;
            let translation = self.transform
                .rot
                .rotate_vector(pan.normalize() * self.movement_speed);
            self.transform.disp += translation;
        }

        let rotation_z = Quaternion::from_angle_z(self.theta);
        let rotation_x = Quaternion::from_angle_x(self.phi);
        self.transform.rot = rotation_z * rotation_x;
        moved
    }

    pub fn mouse_drag(&mut self, delta_x: i32, delta_y: i32) {
        self.moved = true;
        self.theta -= Rad(2. * f32::consts::PI * delta_x as f32 / self.width as f32);
        self.phi -= Rad(2. * f32::consts::PI * delta_y as f32 / self.height as f32);
    }

    pub fn mouse_wheel(&mut self, delta: i32) {
        let sign = delta.signum() as f32;
        self.movement_speed += sign * 0.1 * self.movement_speed;
        self.movement_speed = self.movement_speed.max(0.01);
    }
}
<commit_msg>Use projection matrix from cgmath (#71)<commit_after>// Copyright 2016 The Cartographer Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use cgmath::{Decomposed, Deg, InnerSpace, Matrix4, One, PerspectiveFov, Quaternion, Rad, Rotation,
             Rotation3, Transform, Vector3, Zero};
use opengl;
use std::f32;

#[derive(Debug)]
pub struct Camera {
    pub moving_backward: bool,
    pub moving_forward: bool,
    pub moving_left: bool,
    pub moving_right: bool,
    pub moving_down: bool,
    pub moving_up: bool,
    pub width: i32,
    pub height: i32,

    movement_speed: f32,
    theta: Rad<f32>,
    phi: Rad<f32>,

    moved: bool,
    transform: Decomposed<Vector3<f32>, Quaternion<f32>>,

    projection_matrix: Matrix4<f32>,
}

impl Camera {
    pub fn new(gl: &opengl::Gl, width: i32, height: i32) -> Self {
        let mut camera = Camera {
            movement_speed: 1.5,
            moving_backward: false,
            moving_forward: false,
            moving_left: false,
            moving_right: false,
            moving_down: false,
            moving_up: false,
            moved: true,
            theta: Rad(0.),
            phi: Rad(0.),
            transform: Decomposed {
                scale: 1.,
                rot: Quaternion::one(),
                disp: Vector3::new(0., 0., 150.),
            },

            // These will be set by set_size().
            projection_matrix: One::one(),
            width: 0,
            height: 0,
        };
        camera.set_size(gl, width, height);
        camera
    }

    pub fn set_size(&mut self, gl: &opengl::Gl, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.projection_matrix = Matrix4::from(PerspectiveFov {
            fovy: Rad::from(Deg(45.)),
            aspect: width as f32 / height as f32,
            near: 0.1,
            far: 10000.0,
        });
        unsafe {
            gl.Viewport(0, 0, width, height);
        }
    }

    pub fn get_world_to_gl(&self) -> Matrix4<f32> {
        let world_to_camera: Matrix4<f32> = self.transform.inverse_transform().unwrap().into();
        self.projection_matrix * world_to_camera
    }

    /// Update the camera position for the current frame. Returns true if the camera moved in this
    /// step.
    pub fn update(&mut self) -> bool {
        let mut moved = self.moved;
        self.moved = false;

        let mut pan = Vector3::zero();
        if self.moving_right {
            pan.x += 1.;
        }
        if self.moving_left {
            pan.x -= 1.;
        }
        if self.moving_backward {
            pan.z += 1.;
        }
        if self.moving_forward {
            pan.z -= 1.;
        }
        if self.moving_up {
            pan.y += 1.;
        }
        if self.moving_down {
            pan.y -= 1.;
        }

        if pan.magnitude2() > 0. {
            moved = true;
            let translation = self.transform
                .rot
                .rotate_vector(pan.normalize() * self.movement_speed);
            self.transform.disp += translation;
        }

        let rotation_z = Quaternion::from_angle_z(self.theta);
        let rotation_x = Quaternion::from_angle_x(self.phi);
        self.transform.rot = rotation_z * rotation_x;
        moved
    }

    pub fn mouse_drag(&mut self, delta_x: i32, delta_y: i32) {
        self.moved = true;
        self.theta -= Rad(2. * f32::consts::PI * delta_x as f32 / self.width as f32);
        self.phi -= Rad(2. * f32::consts::PI * delta_y as f32 / self.height as f32);
    }

    pub fn mouse_wheel(&mut self, delta: i32) {
        let sign = delta.signum() as f32;
        self.movement_speed += sign * 0.1 * self.movement_speed;
        self.movement_speed = self.movement_speed.max(0.01);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]

// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]

extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

extern crate syn;
#[macro_use]
extern crate quote;

#[cfg(feature = "with-syntex")]
use std::path::Path;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

mod bound;
mod de;
mod ser;

#[cfg(feature = "with-syntex")]
fn syntex_registry() -> syntex::Registry {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    let mut reg = syntex::Registry::new();

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);

    reg
}

#[cfg(feature = "with-syntex")]
pub fn expand_str(src: &str) -> Result<String, syntex::Error> {
    let src = src.to_owned();

    let expand_thread = move || {
        syntex_registry().expand_str("", "", &src)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    let src = src.as_ref().to_owned();
    let dst = dst.as_ref().to_owned();

    let expand_thread = move || {
        syntex_registry().expand("", src, dst)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}

macro_rules! shim {
    ($name:ident $pkg:ident :: $func:ident) => {
        fn $func(
            cx: &mut ::syntax::ext::base::ExtCtxt,
            _span: ::syntax::codemap::Span,
            meta_item: &::syntax::ast::MetaItem,
            annotatable: &::syntax::ext::base::Annotatable,
            push: &mut FnMut(::syntax::ext::base::Annotatable)
        ) {
            let item = match *annotatable {
                ::syntax::ext::base::Annotatable::Item(ref item) => item,
                _ => {
                    cx.span_err(
                        meta_item.span,
                        concat!("`#[derive(",
                                stringify!($name),
                                ")]` may only be applied to structs and enums"));
                    return;
                }
            };

            use syntax::print::pprust;
            let s = pprust::item_to_string(item);

            let syn_item = syn::parse_macro_input(&s).unwrap();
            let expanded = $pkg::$func(&syn_item).to_string();

            use syntax::parse;
            let name = stringify!($name).to_string();
            let cfg = Vec::new();
            let sess = parse::ParseSess::new();
            let impl_item = parse::parse_item_from_source_str(name, expanded, cfg, &sess);
            push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
        }
    };
}

shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);

#[cfg(feature = "with-syn")]
pub fn expand_single_item(item: &str) -> String {
    let syn_item = syn::parse_macro_input(item).unwrap();
    let (ser, de, syn_item) = strip_serde_derives(syn_item);
    let expanded_ser = if ser {
        Some(ser::expand_derive_serialize(&syn_item))
    } else {
        None
    };
    let expanded_de = if de {
        Some(de::expand_derive_deserialize(&syn_item))
    } else {
        None::<quote::Tokens>
    };
    let syn_item = strip_serde_attrs(syn_item);
    return quote!(#expanded_ser #expanded_de #syn_item).to_string();

    fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
        let mut ser = false;
        let mut de = false;
        let item = syn::MacroInput {
            attrs: item.attrs.into_iter().flat_map(|attr| {
                if attr.is_sugared_doc {
                    return Some(attr);
                }
                let (name, nested) = match attr.value {
                    syn::MetaItem::List(name, nested) => (name, nested),
                    _ => return Some(attr)
                };
                if name != "derive" {
                    return Some(syn::Attribute {
                        value: syn::MetaItem::List(name, nested),
                        is_sugared_doc: false,
                    });
                }
                let rest: Vec<_> = nested.into_iter().filter(|nested| {
                    match *nested {
                        syn::MetaItem::Word(ref word) if word == "Serialize" => {
                            ser = true;
                            false
                        }
                        syn::MetaItem::Word(ref word) if word == "Deserialize" => {
                            de = true;
                            false
                        }
                        _ => true,
                    }
                }).collect();
                if rest.is_empty() {
                    None
                } else {
                    Some(syn::Attribute {
                        value: syn::MetaItem::List(name, rest),
                        is_sugared_doc: false,
                    })
                }
            }).collect(),
            ..item
        };
        (ser, de, item)
    }

    fn strip_serde_attrs(item: syn::MacroInput) -> syn::MacroInput {
        syn::MacroInput {
            attrs: strip_serde_from_attrs(item.attrs),
            body: match item.body {
                syn::Body::Enum(variants) => syn::Body::Enum(
                    variants.into_iter().map(|variant| {
                        syn::Variant {
                            ident: variant.ident,
                            attrs: strip_serde_from_attrs(variant.attrs),
                            data: strip_serde_from_variant_data(variant.data),
                            discriminant: variant.discriminant,
                        }
                    }).collect()
                ),
                syn::Body::Struct(variant_data) => syn::Body::Struct(
                    strip_serde_from_variant_data(variant_data)
                ),
            },
            ..item
        }
    }

    fn strip_serde_from_variant_data(data: syn::VariantData) -> syn::VariantData {
        match data {
            syn::VariantData::Struct(fields) => syn::VariantData::Struct(
                fields.into_iter().map(strip_serde_from_field).collect()
            ),
            syn::VariantData::Tuple(fields) => syn::VariantData::Tuple(
                fields.into_iter().map(strip_serde_from_field).collect()
            ),
            syn::VariantData::Unit => syn::VariantData::Unit,
        }
    }

    fn strip_serde_from_field(field: syn::Field) -> syn::Field {
        syn::Field {
            attrs: strip_serde_from_attrs(field.attrs),
            ..field
        }
    }

    fn strip_serde_from_attrs(attrs: Vec<syn::Attribute>) -> Vec<syn::Attribute> {
        attrs.into_iter().filter(|attr| {
            match attr.value {
                syn::MetaItem::List(ref ident, _) => ident != "serde",
                _ => true,
            }
        }).collect()
    }
}
<commit_msg>Mark all serde attributes as used<commit_after>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]

// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]

extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

extern crate syn;
#[macro_use]
extern crate quote;

#[cfg(feature = "with-syntex")]
use std::path::Path;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

mod bound;
mod de;
mod ser;

#[cfg(feature = "with-syntex")]
fn syntex_registry() -> syntex::Registry {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    let mut reg = syntex::Registry::new();

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);

    reg
}

#[cfg(feature = "with-syntex")]
pub fn expand_str(src: &str) -> Result<String, syntex::Error> {
    let src = src.to_owned();

    let expand_thread = move || {
        syntex_registry().expand_str("", "", &src)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    let src = src.as_ref().to_owned();
    let dst = dst.as_ref().to_owned();

    let expand_thread = move || {
        syntex_registry().expand("", src, dst)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}

macro_rules! shim {
    ($name:ident $pkg:ident :: $func:ident) => {
        fn $func(
            cx: &mut ::syntax::ext::base::ExtCtxt,
            _span: ::syntax::codemap::Span,
            meta_item: &::syntax::ast::MetaItem,
            annotatable: &::syntax::ext::base::Annotatable,
            push: &mut FnMut(::syntax::ext::base::Annotatable)
        ) {
            let item = match *annotatable {
                ::syntax::ext::base::Annotatable::Item(ref item) => item,
                _ => {
                    cx.span_err(
                        meta_item.span,
                        concat!("`#[derive(",
                                stringify!($name),
                                ")]` may only be applied to structs and enums"));
                    return;
                }
            };

            use syntax::{attr, ast, visit};
            struct MarkSerdeAttributesUsed;
            impl visit::Visitor for MarkSerdeAttributesUsed {
                fn visit_attribute(&mut self, attr: &ast::Attribute) {
                    match attr.node.value.node {
                        ast::MetaItemKind::List(ref name, _) if name == "serde" => {
                            attr::mark_used(attr);
                        }
                        _ => {}
                    }
                }
            }
            visit::walk_item(&mut MarkSerdeAttributesUsed, item);

            use syntax::print::pprust;
            let s = pprust::item_to_string(item);

            let syn_item = syn::parse_macro_input(&s).unwrap();
            let expanded = $pkg::$func(&syn_item).to_string();

            use syntax::parse;
            let name = stringify!($name).to_string();
            let cfg = Vec::new();
            let sess = parse::ParseSess::new();
            let impl_item = parse::parse_item_from_source_str(name, expanded, cfg, &sess);
            push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
        }
    };
}

shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize);

#[cfg(feature = "with-syn")]
pub fn expand_single_item(item: &str) -> String {
    let syn_item = syn::parse_macro_input(item).unwrap();
    let (ser, de, syn_item) = strip_serde_derives(syn_item);
    let expanded_ser = if ser {
        Some(ser::expand_derive_serialize(&syn_item))
    } else {
        None
    };
    let expanded_de = if de {
        Some(de::expand_derive_deserialize(&syn_item))
    } else {
        None::<quote::Tokens>
    };
    let syn_item = strip_serde_attrs(syn_item);
    return quote!(#expanded_ser #expanded_de #syn_item).to_string();

    fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
        let mut ser = false;
        let mut de = false;
        let item = syn::MacroInput {
            attrs: item.attrs.into_iter().flat_map(|attr| {
                if attr.is_sugared_doc {
                    return Some(attr);
                }
                let (name, nested) = match attr.value {
                    syn::MetaItem::List(name, nested) => (name, nested),
                    _ => return Some(attr)
                };
                if name != "derive" {
                    return Some(syn::Attribute {
                        value: syn::MetaItem::List(name, nested),
                        is_sugared_doc: false,
                    });
                }
                let rest: Vec<_> = nested.into_iter().filter(|nested| {
                    match *nested {
                        syn::MetaItem::Word(ref word) if word == "Serialize" => {
                            ser = true;
                            false
                        }
                        syn::MetaItem::Word(ref word) if word == "Deserialize" => {
                            de = true;
                            false
                        }
                        _ => true,
                    }
                }).collect();
                if rest.is_empty() {
                    None
                } else {
                    Some(syn::Attribute {
                        value: syn::MetaItem::List(name, rest),
                        is_sugared_doc: false,
                    })
                }
            }).collect(),
            ..item
        };
        (ser, de, item)
    }

    fn strip_serde_attrs(item: syn::MacroInput) -> syn::MacroInput {
        syn::MacroInput {
            attrs: strip_serde_from_attrs(item.attrs),
            body: match item.body {
                syn::Body::Enum(variants) => syn::Body::Enum(
                    variants.into_iter().map(|variant| {
                        syn::Variant {
                            ident: variant.ident,
                            attrs: strip_serde_from_attrs(variant.attrs),
                            data: strip_serde_from_variant_data(variant.data),
                            discriminant: variant.discriminant,
                        }
                    }).collect()
                ),
                syn::Body::Struct(variant_data) => syn::Body::Struct(
                    strip_serde_from_variant_data(variant_data)
                ),
            },
            ..item
        }
    }

    fn strip_serde_from_variant_data(data: syn::VariantData) -> syn::VariantData {
        match data {
            syn::VariantData::Struct(fields) => syn::VariantData::Struct(
                fields.into_iter().map(strip_serde_from_field).collect()
            ),
            syn::VariantData::Tuple(fields) => syn::VariantData::Tuple(
                fields.into_iter().map(strip_serde_from_field).collect()
            ),
            syn::VariantData::Unit => syn::VariantData::Unit,
        }
    }

    fn strip_serde_from_field(field: syn::Field) -> syn::Field {
        syn::Field {
            attrs: strip_serde_from_attrs(field.attrs),
            ..field
        }
    }

    fn strip_serde_from_attrs(attrs: Vec<syn::Attribute>) -> Vec<syn::Attribute> {
        attrs.into_iter().filter(|attr| {
            match attr.value {
                syn::MetaItem::List(ref ident, _) => ident != "serde",
                _ => true,
            }
        }).collect()
    }
}
<|endoftext|>


<commit_before>use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, App, HttpResponse, Responder};
use actix_web_codegen::{get, post, put};
use futures::{future, Future};

#[get("/test")]
fn test() -> impl Responder {
    HttpResponse::Ok()
}

#[put("/test")]
fn put_test() -> impl Responder {
    HttpResponse::Created()
}

#[post("/test")]
fn post_test() -> impl Responder {
    HttpResponse::NoContent()
}

#[get("/test")]
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[get("/test")]
fn auto_sync() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[test]
fn test_body() {
    let mut srv = TestServer::new(|| {
        HttpService::new(
            App::new()
                .service(post_test)
                .service(put_test)
                .service(test),
        )
    });
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());

    let request = srv.request(http::Method::PUT, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::CREATED);

    let request = srv.request(http::Method::POST, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::NO_CONTENT);

    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_sync)));
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}

#[test]
fn test_auto_async() {
    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_async)));

    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}
<commit_msg>When using codegen with paths that have parameters then only the first endpoint resolves (#842)<commit_after>use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, App, HttpResponse, Responder, web::{Path}};
use actix_web_codegen::{get, post, put, delete};
use futures::{future, Future};

#[get("/test")]
fn test() -> impl Responder {
    HttpResponse::Ok()
}

#[put("/test")]
fn put_test() -> impl Responder {
    HttpResponse::Created()
}

#[post("/test")]
fn post_test() -> impl Responder {
    HttpResponse::NoContent()
}

#[get("/test")]
fn auto_async() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[get("/test")]
fn auto_sync() -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    future::ok(HttpResponse::Ok().finish())
}

#[put("/test/{param}")]
fn put_param_test(_: Path<String>) -> impl Responder {
    HttpResponse::Created()
}

#[delete("/test/{param}")]
fn delete_param_test(_: Path<String>) -> impl Responder {
    HttpResponse::NoContent()
}

#[get("/test/{param}")]
fn get_param_test(_: Path<String>) -> impl Responder {
    HttpResponse::Ok()
}

#[test]
fn test_params() {
    let mut srv = TestServer::new(|| {
        HttpService::new(
            App::new()
                .service(get_param_test)
                .service(put_param_test)
                .service(delete_param_test),
        )
    });

    let request = srv.request(http::Method::GET, srv.url("/test/it"));
    let response = srv.block_on(request.send()).unwrap();
    assert_eq!(response.status(), http::StatusCode::OK);

    let request = srv.request(http::Method::PUT, srv.url("/test/it"));
    let response = srv.block_on(request.send()).unwrap();
    assert_eq!(response.status(), http::StatusCode::CREATED);

    let request = srv.request(http::Method::DELETE, srv.url("/test/it"));
    let response = srv.block_on(request.send()).unwrap();
    assert_eq!(response.status(), http::StatusCode::NO_CONTENT);
}

#[test]
fn test_body() {
    let mut srv = TestServer::new(|| {
        HttpService::new(
            App::new()
                .service(post_test)
                .service(put_test)
                .service(test),
        )
    });
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());

    let request = srv.request(http::Method::PUT, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::CREATED);

    let request = srv.request(http::Method::POST, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
    assert_eq!(response.status(), http::StatusCode::NO_CONTENT);

    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_sync)));
    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}

#[test]
fn test_auto_async() {
    let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_async)));

    let request = srv.request(http::Method::GET, srv.url("/test"));
    let response = srv.block_on(request.send()).unwrap();
    assert!(response.status().is_success());
}
<|endoftext|>