<commit_before>//! Implementation of input backend trait for types provided by `libinput`

use backend::SeatInternal;
use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities, MouseButton};
use input::{Libinput, Device, Seat as LibinputSeat, DeviceCapability};
use input::event::*;

use std::io::Error as IoError;
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
use std::hash::{Hash, Hasher};

struct SeatDesc {
    seat: Seat,
    pointer: (u32, u32),
}

pub struct LibinputInputBackend {
    context: Libinput,
    devices: Vec<Device>,
    seats: HashMap<LibinputSeat, SeatDesc>,
    handler: Option<Box<InputHandler<LibinputInputBackend> + 'static>>,
    logger: ::slog::Logger,
}

impl InputBackend for LibinputInputBackend {
    type InputConfig = [Device];
    type EventError = IoError;

    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, mut handler: H) {
        if self.handler.is_some() {
            self.clear_handler();
        }
        info!(self.logger, "New input handler set.");
        for desc in self.seats.values() {
            trace!(self.logger, "Calling on_seat_created with {:?}", desc.seat);
            handler.on_seat_created(&desc.seat);
        }
        self.handler = Some(Box::new(handler));
    }

    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>> {
        self.handler
            .as_mut()
            .map(|handler| handler as &mut InputHandler<Self>)
    }

    fn clear_handler(&mut self) {
        if let Some(mut handler) = self.handler.take() {
            for desc in self.seats.values() {
                trace!(self.logger, "Calling on_seat_destroyed with {:?}", desc.seat);
                handler.on_seat_destroyed(&desc.seat);
            }
            info!(self.logger, "Removing input handler");
        }
    }

    fn input_config(&mut self) -> &mut Self::InputConfig {
        &mut self.devices
    }

    fn set_cursor_position(&mut self, _x: u32, _y: u32) -> Result<(), ()> {
        // FIXME later.
        // This will be doable with the hardware cursor api and probably some more cases
        warn!(self.logger, "Setting the cursor position is currently unsupported by the libinput backend");
        Err(())
    }

    fn dispatch_new_events(&mut self) -> Result<(), IoError> {
        self.context.dispatch()?;
        for event in &mut self.context {
            match event {
                Event::Device(device_event) => {
                    use input::event::device::*;
                    match device_event {
                        DeviceEvent::Added(device_added_event) => {
                            let added = device_added_event.into_event().device();

                            let new_caps = SeatCapabilities {
                                pointer: added.has_capability(DeviceCapability::Pointer),
                                keyboard: added.has_capability(DeviceCapability::Keyboard),
                                touch: added.has_capability(DeviceCapability::Touch),
                            };

                            let device_seat = added.seat();
                            self.devices.push(added);

                            match self.seats.entry(device_seat) {
                                Entry::Occupied(mut seat_entry) => {
                                    let old_seat = seat_entry.get_mut();
                                    {
                                        let caps = old_seat.seat.capabilities_mut();
                                        caps.pointer = new_caps.pointer || caps.pointer;
                                        caps.keyboard = new_caps.keyboard || caps.keyboard;
                                        caps.touch = new_caps.touch || caps.touch;
                                    }
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_changed with {:?}", old_seat.seat);
                                        handler.on_seat_changed(&old_seat.seat);
                                    }
                                },
                                Entry::Vacant(seat_entry) => {
                                    let mut hasher = DefaultHasher::default();
                                    seat_entry.key().hash(&mut hasher);
                                    let desc = seat_entry.insert(SeatDesc {
                                        seat: Seat::new(hasher.finish(), new_caps),
                                        pointer: (0, 0) //FIXME: What position to assume? Maybe center of the screen instead. Probably call `set_cursor_position` after this.
                                    });
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_created with {:?}", desc.seat);
                                        handler.on_seat_created(&desc.seat);
                                    }
                                }
                            }
                        },
                        DeviceEvent::Removed(device_removed_event) => {
                            let removed = device_removed_event.into_event().device();

                            // remove device
                            self.devices.retain(|dev| *dev == removed);

                            let device_seat = removed.seat();

                            // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
                            if let Some(desc) = self.seats.get_mut(&device_seat) {
                                let caps = desc.seat.capabilities_mut();
                                caps.pointer = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Pointer));
                                caps.keyboard = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Keyboard));
                                caps.touch = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Touch));
                            } else {
                                panic!("Seat changed that was never created")
                            }

                            // check if the seat has any other devices
                            if !self.devices.iter().any(|x| x.seat() == device_seat) {
                                // it has not, lets destroy it
                                if let Some(desc) = self.seats.remove(&device_seat) {
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_destroyed with {:?}", desc.seat);
                                        handler.on_seat_destroyed(&desc.seat);
                                    }
                                } else {
                                    panic!("Seat destroyed that was never created");
                                }
                            } else {
                                // it has, notify about updates
                                if let Some(ref mut handler) = self.handler {
                                    let desc = self.seats.get(&device_seat).unwrap();
                                    trace!(self.logger, "Calling on_seat_changed with {:?}", desc.seat);
                                    handler.on_seat_changed(&desc.seat);
                                }
                            }
                        },
                    }
                    if let Some(ref mut handler) = self.handler {
                       handler.on_input_config_changed(&mut self.devices);
                    }
                },
                Event::Touch(touch_event) => {
                    use ::input::event::touch::*;
                    if let Some(ref mut handler) = self.handler {
                        let device_seat = touch_event.device().seat();
                        trace!(self.logger, "Calling on_touch with {:?}", touch_event);
                        handler.on_touch(&self.seats.get(&device_seat).expect("Recieved key event of non existing Seat").seat,
                                         touch_event.time(), touch_event.into())
                    }
                },
                Event::Keyboard(keyboard_event) => {
                    use ::input::event::keyboard::*;
                    match keyboard_event {
                        KeyboardEvent::Key(key_event) => {
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event);
                                let device_seat = key_event.device().seat();
                                handler.on_keyboard_key(&self.seats.get(&device_seat).expect("Recieved key event of non existing Seat").seat,
                                                        key_event.time(), key_event.key(), key_event.key_state().into(), key_event.seat_key_count());
                            }
                        }
                    }
                },
                Event::Pointer(pointer_event) => {
                    use ::input::event::pointer::*;
                    match pointer_event {
                        PointerEvent::Motion(motion_event) => {
                            let device_seat = motion_event.device().seat();
                            let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                            desc.pointer.0 += motion_event.dx() as u32;
                            desc.pointer.1 += motion_event.dy() as u32;
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_pointer_move with {:?}", desc.pointer);
                                handler.on_pointer_move(&desc.seat, motion_event.time(), desc.pointer);
                            }
                        },
                        PointerEvent::MotionAbsolute(motion_event) => {
                            let device_seat = motion_event.device().seat();
                            let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                            desc.pointer = (
                                motion_event.absolute_x_transformed(
                                /*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280) as u32,
                                motion_event.absolute_y_transformed(
                                /*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800) as u32,
                            );
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_pointer_move with {:?}", desc.pointer);
                                handler.on_pointer_move(&desc.seat, motion_event.time(), desc.pointer);
                            }
                        },
                        PointerEvent::Axis(axis_event) => {
                            if let Some(ref mut handler) = self.handler {
                                let device_seat = axis_event.device().seat();
                                let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                                if axis_event.has_axis(Axis::Vertical) {
                                    let value = match axis_event.axis_source() {
                                        AxisSource::Finger | AxisSource::Continuous => axis_event.axis_value(Axis::Vertical),
                                        AxisSource::Wheel | AxisSource::WheelTilt => axis_event.axis_value_discrete(Axis::Vertical).unwrap(),
                                    };
                                    trace!(self.logger, "Calling on_pointer_scroll on Axis::Vertical from {:?} with {:?}", axis_event.axis_source(), value);
                                    handler.on_pointer_scroll(&desc.seat, axis_event.time(), ::backend::input::Axis::Vertical,
                                                              axis_event.axis_source().into(), value);
                                }
                                if axis_event.has_axis(Axis::Horizontal) {
                                    let value = match axis_event.axis_source() {
                                        AxisSource::Finger | AxisSource::Continuous => axis_event.axis_value(Axis::Horizontal),
                                        AxisSource::Wheel | AxisSource::WheelTilt => axis_event.axis_value_discrete(Axis::Horizontal).unwrap(),
                                    };
                                    trace!(self.logger, "Calling on_pointer_scroll on Axis::Horizontal from {:?} with {:?}", axis_event.axis_source(), value);
                                    handler.on_pointer_scroll(&desc.seat, axis_event.time(), ::backend::input::Axis::Horizontal,
                                                              axis_event.axis_source().into(), value);
                                }
                            }
                        },
                        PointerEvent::Button(button_event) => {
                            if let Some(ref mut handler) = self.handler {
                                let device_seat = button_event.device().seat();
                                let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                                trace!(self.logger, "Calling on_pointer_button with {:?}", button_event.button());
                                handler.on_pointer_button(&desc.seat, button_event.time(), match button_event.button() {
                                    0x110 => MouseButton::Left,
                                    0x111 => MouseButton::Right,
                                    0x112 => MouseButton::Middle,
                                    x => MouseButton::Other(x as u8),
                                }, button_event.button_state().into());
                            }
                        }
                    }
                },
                _ => {}, //FIXME: What to do with the rest.
            }
        };
        Ok(())
    }
}

impl From<::input::event::keyboard::KeyState> for ::backend::input::KeyState {
    fn from(libinput: ::input::event::keyboard::KeyState) -> Self {
        match libinput {
            ::input::event::keyboard::KeyState::Pressed => ::backend::input::KeyState::Pressed,
            ::input::event::keyboard::KeyState::Released => ::backend::input::KeyState::Released,
        }
    }
}

impl From<::input::event::pointer::AxisSource> for ::backend::input::AxisSource {
    fn from(libinput: ::input::event::pointer::AxisSource) -> Self {
        match libinput {
            ::input::event::pointer::AxisSource::Finger => ::backend::input::AxisSource::Finger,
            ::input::event::pointer::AxisSource::Continuous => ::backend::input::AxisSource::Continuous,
            ::input::event::pointer::AxisSource::Wheel => ::backend::input::AxisSource::Wheel,
            ::input::event::pointer::AxisSource::WheelTilt => ::backend::input::AxisSource::WheelTilt,
        }
    }
}

impl From<::input::event::pointer::ButtonState> for ::backend::input::MouseButtonState {
    fn from(libinput: ::input::event::pointer::ButtonState) -> Self {
        match libinput {
            ::input::event::pointer::ButtonState::Pressed => ::backend::input::MouseButtonState::Pressed,
            ::input::event::pointer::ButtonState::Released => ::backend::input::MouseButtonState::Released,
        }
    }
}

impl From<::input::event::touch::TouchEvent> for ::backend::input::TouchEvent {
    fn from(libinput: ::input::event::touch::TouchEvent) -> Self {
        use ::input::event::touch::{TouchEventSlot, TouchEventPosition};
        use ::backend::TouchSlotInternal;

        match libinput {
            ::input::event::touch::TouchEvent::Down(down_event) => ::backend::input::TouchEvent::Down {
                slot: down_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
                x: down_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280),
                y: down_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800),
            },
            ::input::event::touch::TouchEvent::Motion(motion_event) => ::backend::input::TouchEvent::Motion {
                slot: motion_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
                x: motion_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280),
                y: motion_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800),
            },
            ::input::event::touch::TouchEvent::Up(up_event) => ::backend::input::TouchEvent::Up {
                slot: up_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
            },
            ::input::event::touch::TouchEvent::Cancel(cancel_event) => ::backend::input::TouchEvent::Cancel {
                slot: cancel_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
            },
            ::input::event::touch::TouchEvent::Frame(_) => ::backend::input::TouchEvent::Frame,
        }
    }
}
<commit_msg>Add initializer<commit_after>//! Implementation of input backend trait for types provided by `libinput`

use backend::SeatInternal;
use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities, MouseButton};
use input::{Libinput, Device, Seat as LibinputSeat, DeviceCapability};
use input::event::*;

use std::io::Error as IoError;
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
use std::hash::{Hash, Hasher};

struct SeatDesc {
    seat: Seat,
    pointer: (u32, u32),
}

pub struct LibinputInputBackend {
    context: Libinput,
    devices: Vec<Device>,
    seats: HashMap<LibinputSeat, SeatDesc>,
    handler: Option<Box<InputHandler<LibinputInputBackend> + 'static>>,
    logger: ::slog::Logger,
}

impl LibinputInputBackend {
    pub fn new<L>(context: Libinput, logger: L) -> Self
        where L: Into<Option<::slog::Logger>>
    {
        let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_libinput"));
        info!(log, "Initializing a libinput backend");
        LibinputInputBackend {
            context: context,
            devices: Vec::new(),
            seats: HashMap::new(),
            handler: None,
            logger: log,
        }
    }
}

impl InputBackend for LibinputInputBackend {
    type InputConfig = [Device];
    type EventError = IoError;

    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, mut handler: H) {
        if self.handler.is_some() {
            self.clear_handler();
        }
        info!(self.logger, "New input handler set.");
        for desc in self.seats.values() {
            trace!(self.logger, "Calling on_seat_created with {:?}", desc.seat);
            handler.on_seat_created(&desc.seat);
        }
        self.handler = Some(Box::new(handler));
    }

    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>> {
        self.handler
            .as_mut()
            .map(|handler| handler as &mut InputHandler<Self>)
    }

    fn clear_handler(&mut self) {
        if let Some(mut handler) = self.handler.take() {
            for desc in self.seats.values() {
                trace!(self.logger, "Calling on_seat_destroyed with {:?}", desc.seat);
                handler.on_seat_destroyed(&desc.seat);
            }
            info!(self.logger, "Removing input handler");
        }
    }

    fn input_config(&mut self) -> &mut Self::InputConfig {
        &mut self.devices
    }

    fn set_cursor_position(&mut self, _x: u32, _y: u32) -> Result<(), ()> {
        // FIXME later.
        // This will be doable with the hardware cursor api and probably some more cases
        warn!(self.logger, "Setting the cursor position is currently unsupported by the libinput backend");
        Err(())
    }

    fn dispatch_new_events(&mut self) -> Result<(), IoError> {
        self.context.dispatch()?;
        for event in &mut self.context {
            match event {
                Event::Device(device_event) => {
                    use input::event::device::*;
                    match device_event {
                        DeviceEvent::Added(device_added_event) => {
                            let added = device_added_event.into_event().device();

                            let new_caps = SeatCapabilities {
                                pointer: added.has_capability(DeviceCapability::Pointer),
                                keyboard: added.has_capability(DeviceCapability::Keyboard),
                                touch: added.has_capability(DeviceCapability::Touch),
                            };

                            let device_seat = added.seat();
                            self.devices.push(added);

                            match self.seats.entry(device_seat) {
                                Entry::Occupied(mut seat_entry) => {
                                    let old_seat = seat_entry.get_mut();
                                    {
                                        let caps = old_seat.seat.capabilities_mut();
                                        caps.pointer = new_caps.pointer || caps.pointer;
                                        caps.keyboard = new_caps.keyboard || caps.keyboard;
                                        caps.touch = new_caps.touch || caps.touch;
                                    }
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_changed with {:?}", old_seat.seat);
                                        handler.on_seat_changed(&old_seat.seat);
                                    }
                                },
                                Entry::Vacant(seat_entry) => {
                                    let mut hasher = DefaultHasher::default();
                                    seat_entry.key().hash(&mut hasher);
                                    let desc = seat_entry.insert(SeatDesc {
                                        seat: Seat::new(hasher.finish(), new_caps),
                                        pointer: (0, 0) //FIXME: What position to assume? Maybe center of the screen instead. Probably call `set_cursor_position` after this.
                                    });
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_created with {:?}", desc.seat);
                                        handler.on_seat_created(&desc.seat);
                                    }
                                }
                            }
                        },
                        DeviceEvent::Removed(device_removed_event) => {
                            let removed = device_removed_event.into_event().device();

                            // remove device
                            self.devices.retain(|dev| *dev == removed);

                            let device_seat = removed.seat();

                            // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
                            if let Some(desc) = self.seats.get_mut(&device_seat) {
                                let caps = desc.seat.capabilities_mut();
                                caps.pointer = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Pointer));
                                caps.keyboard = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Keyboard));
                                caps.touch = self.devices.iter().filter(|x| x.seat() == device_seat).any(|x| x.has_capability(DeviceCapability::Touch));
                            } else {
                                panic!("Seat changed that was never created")
                            }

                            // check if the seat has any other devices
                            if !self.devices.iter().any(|x| x.seat() == device_seat) {
                                // it has not, lets destroy it
                                if let Some(desc) = self.seats.remove(&device_seat) {
                                    if let Some(ref mut handler) = self.handler {
                                        trace!(self.logger, "Calling on_seat_destroyed with {:?}", desc.seat);
                                        handler.on_seat_destroyed(&desc.seat);
                                    }
                                } else {
                                    panic!("Seat destroyed that was never created");
                                }
                            } else {
                                // it has, notify about updates
                                if let Some(ref mut handler) = self.handler {
                                    let desc = self.seats.get(&device_seat).unwrap();
                                    trace!(self.logger, "Calling on_seat_changed with {:?}", desc.seat);
                                    handler.on_seat_changed(&desc.seat);
                                }
                            }
                        },
                    }
                    if let Some(ref mut handler) = self.handler {
                       handler.on_input_config_changed(&mut self.devices);
                    }
                },
                Event::Touch(touch_event) => {
                    use ::input::event::touch::*;
                    if let Some(ref mut handler) = self.handler {
                        let device_seat = touch_event.device().seat();
                        trace!(self.logger, "Calling on_touch with {:?}", touch_event);
                        handler.on_touch(&self.seats.get(&device_seat).expect("Recieved key event of non existing Seat").seat,
                                         touch_event.time(), touch_event.into())
                    }
                },
                Event::Keyboard(keyboard_event) => {
                    use ::input::event::keyboard::*;
                    match keyboard_event {
                        KeyboardEvent::Key(key_event) => {
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event);
                                let device_seat = key_event.device().seat();
                                handler.on_keyboard_key(&self.seats.get(&device_seat).expect("Recieved key event of non existing Seat").seat,
                                                        key_event.time(), key_event.key(), key_event.key_state().into(), key_event.seat_key_count());
                            }
                        }
                    }
                },
                Event::Pointer(pointer_event) => {
                    use ::input::event::pointer::*;
                    match pointer_event {
                        PointerEvent::Motion(motion_event) => {
                            let device_seat = motion_event.device().seat();
                            let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                            desc.pointer.0 += motion_event.dx() as u32;
                            desc.pointer.1 += motion_event.dy() as u32;
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_pointer_move with {:?}", desc.pointer);
                                handler.on_pointer_move(&desc.seat, motion_event.time(), desc.pointer);
                            }
                        },
                        PointerEvent::MotionAbsolute(motion_event) => {
                            let device_seat = motion_event.device().seat();
                            let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                            desc.pointer = (
                                motion_event.absolute_x_transformed(
                                /*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280) as u32,
                                motion_event.absolute_y_transformed(
                                /*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800) as u32,
                            );
                            if let Some(ref mut handler) = self.handler {
                                trace!(self.logger, "Calling on_pointer_move with {:?}", desc.pointer);
                                handler.on_pointer_move(&desc.seat, motion_event.time(), desc.pointer);
                            }
                        },
                        PointerEvent::Axis(axis_event) => {
                            if let Some(ref mut handler) = self.handler {
                                let device_seat = axis_event.device().seat();
                                let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                                if axis_event.has_axis(Axis::Vertical) {
                                    let value = match axis_event.axis_source() {
                                        AxisSource::Finger | AxisSource::Continuous => axis_event.axis_value(Axis::Vertical),
                                        AxisSource::Wheel | AxisSource::WheelTilt => axis_event.axis_value_discrete(Axis::Vertical).unwrap(),
                                    };
                                    trace!(self.logger, "Calling on_pointer_scroll on Axis::Vertical from {:?} with {:?}", axis_event.axis_source(), value);
                                    handler.on_pointer_scroll(&desc.seat, axis_event.time(), ::backend::input::Axis::Vertical,
                                                              axis_event.axis_source().into(), value);
                                }
                                if axis_event.has_axis(Axis::Horizontal) {
                                    let value = match axis_event.axis_source() {
                                        AxisSource::Finger | AxisSource::Continuous => axis_event.axis_value(Axis::Horizontal),
                                        AxisSource::Wheel | AxisSource::WheelTilt => axis_event.axis_value_discrete(Axis::Horizontal).unwrap(),
                                    };
                                    trace!(self.logger, "Calling on_pointer_scroll on Axis::Horizontal from {:?} with {:?}", axis_event.axis_source(), value);
                                    handler.on_pointer_scroll(&desc.seat, axis_event.time(), ::backend::input::Axis::Horizontal,
                                                              axis_event.axis_source().into(), value);
                                }
                            }
                        },
                        PointerEvent::Button(button_event) => {
                            if let Some(ref mut handler) = self.handler {
                                let device_seat = button_event.device().seat();
                                let desc = self.seats.get_mut(&device_seat).expect("Recieved pointer event of non existing Seat");
                                trace!(self.logger, "Calling on_pointer_button with {:?}", button_event.button());
                                handler.on_pointer_button(&desc.seat, button_event.time(), match button_event.button() {
                                    0x110 => MouseButton::Left,
                                    0x111 => MouseButton::Right,
                                    0x112 => MouseButton::Middle,
                                    x => MouseButton::Other(x as u8),
                                }, button_event.button_state().into());
                            }
                        }
                    }
                },
                _ => {}, //FIXME: What to do with the rest.
            }
        };
        Ok(())
    }
}

impl From<::input::event::keyboard::KeyState> for ::backend::input::KeyState {
    fn from(libinput: ::input::event::keyboard::KeyState) -> Self {
        match libinput {
            ::input::event::keyboard::KeyState::Pressed => ::backend::input::KeyState::Pressed,
            ::input::event::keyboard::KeyState::Released => ::backend::input::KeyState::Released,
        }
    }
}

impl From<::input::event::pointer::AxisSource> for ::backend::input::AxisSource {
    fn from(libinput: ::input::event::pointer::AxisSource) -> Self {
        match libinput {
            ::input::event::pointer::AxisSource::Finger => ::backend::input::AxisSource::Finger,
            ::input::event::pointer::AxisSource::Continuous => ::backend::input::AxisSource::Continuous,
            ::input::event::pointer::AxisSource::Wheel => ::backend::input::AxisSource::Wheel,
            ::input::event::pointer::AxisSource::WheelTilt => ::backend::input::AxisSource::WheelTilt,
        }
    }
}

impl From<::input::event::pointer::ButtonState> for ::backend::input::MouseButtonState {
    fn from(libinput: ::input::event::pointer::ButtonState) -> Self {
        match libinput {
            ::input::event::pointer::ButtonState::Pressed => ::backend::input::MouseButtonState::Pressed,
            ::input::event::pointer::ButtonState::Released => ::backend::input::MouseButtonState::Released,
        }
    }
}

impl From<::input::event::touch::TouchEvent> for ::backend::input::TouchEvent {
    fn from(libinput: ::input::event::touch::TouchEvent) -> Self {
        use ::input::event::touch::{TouchEventSlot, TouchEventPosition};
        use ::backend::TouchSlotInternal;

        match libinput {
            ::input::event::touch::TouchEvent::Down(down_event) => ::backend::input::TouchEvent::Down {
                slot: down_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
                x: down_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280),
                y: down_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800),
            },
            ::input::event::touch::TouchEvent::Motion(motion_event) => ::backend::input::TouchEvent::Motion {
                slot: motion_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
                x: motion_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).width() or something like that*/ 1280),
                y: motion_event.x_transformed(/*FIXME: global.get_focused_output_for_seat(&desc.seat).height() or something like that*/ 800),
            },
            ::input::event::touch::TouchEvent::Up(up_event) => ::backend::input::TouchEvent::Up {
                slot: up_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
            },
            ::input::event::touch::TouchEvent::Cancel(cancel_event) => ::backend::input::TouchEvent::Cancel {
                slot: cancel_event.slot().map(|x| ::backend::input::TouchSlot::new(x)),
            },
            ::input::event::touch::TouchEvent::Frame(_) => ::backend::input::TouchEvent::Frame,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(old_path)]
#![feature(collections)]

extern crate elf;

use std::old_path::Path;

fn main() {
    let path = Path::new("stress");
    let file = match elf::File::open(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };
    println!("Debug-print ELF file:");
    println!("{:?}", file);
    println!("");
    println!("Pretty-print ELF file:");
    println!("{}", file);

    println!("Getting the .text section");
    let text = file.get_section(String::from_str(".text"));
    match text {
        Some(s) => println!("shdr: {}", s),
        None => println!("Failed to look up .text section!"),
    }
}
<commit_msg>Remove binary.<commit_after><|endoftext|>


<commit_before>//! `cargo upgrade`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate cargo_metadata;
extern crate docopt;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate serde_derive;
extern crate toml_edit;

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::io::Write;
use std::process;

extern crate cargo_edit;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};

extern crate termcolor;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
            CargoMetadata(::cargo_metadata::Error, ::cargo_metadata::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r"
Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).

Usage:
    cargo upgrade [options]
    cargo upgrade [options] <dependency>... [--precise <PRECISE>]
    cargo upgrade (-h | --help)
    cargo upgrade (-V | --version)

Options:
    --all                       Upgrade all packages in the workspace.
    --precise PRECISE           Upgrade dependencies to exactly PRECISE.
    --manifest-path PATH        Path to the manifest to upgrade.
    --allow-prerelease          Include prerelease versions when fetching from crates.io (e.g.
                                '0.6.0-alpha'). Defaults to false.
    --dry-run                   Print changes to be made without making them. Defaults to false.
    -h --help                   Show this help page.
    -V --version                Show version.

This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.
";

/// Docopts input args.
#[derive(Debug, Deserialize)]
struct Args {
    /// `<dependency>...`
    arg_dependency: Vec<String>,
    /// `--precise PRECISE`
    flag_precise: Option<String>,
    /// `--manifest-path PATH`
    flag_manifest_path: Option<String>,
    /// `--all`
    flag_all: bool,
    /// `--allow-prerelease`
    flag_allow_prerelease: bool,
    /// `--dry-run`
    flag_dry_run: bool,
    /// `--version`
    flag_version: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);

        cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Failed to get workspace metadata")?
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let packages = cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Invalid manifest")?
            .packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| "Found virtual manifest, but this command requires running against an \
                           actual package in this workspace. Try adding `--all`.")?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the combined set of dependencies of the manifests.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<InputDependencies> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(InputDependencies(if only_update.is_empty() {
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    ///  Upgrade the manifests on disk. They will upgrade using the new dependencies provided.
    fn upgrade(self, upgraded_deps: &ResolvedDependencies, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, _) in self.0 {
            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to upgrade.
struct InputDependencies(HashMap<String, Option<String>>);

/// The set of dependencies to upgrade alongside the new version of each.
struct ResolvedDependencies(HashMap<String, String>);

impl InputDependencies {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(
        self,
        precise: &Option<String>,
        allow_prerelease: bool,
    ) -> Result<ResolvedDependencies> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else if let Some(ref v) = *precise {
                    Ok((name, v.clone()))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ResolvedDependencies)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        arg_dependency,
        flag_precise,
        flag_manifest_path,
        flag_all,
        flag_allow_prerelease,
        flag_dry_run,
        ..
    } = args;

    let manifests = if flag_all {
        Manifests::get_all(&flag_manifest_path)
    } else {
        Manifests::get_local_one(&flag_manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(arg_dependency)?;

    let upgraded_dependencies =
        existing_dependencies.get_upgraded(&flag_precise, flag_allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, flag_dry_run)
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-upgrade version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>Make comments clearer<commit_after>//! `cargo upgrade`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate cargo_metadata;
extern crate docopt;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate serde_derive;
extern crate toml_edit;

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::io::Write;
use std::process;

extern crate cargo_edit;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};

extern crate termcolor;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
            CargoMetadata(::cargo_metadata::Error, ::cargo_metadata::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r"
Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).

Usage:
    cargo upgrade [options]
    cargo upgrade [options] <dependency>... [--precise <PRECISE>]
    cargo upgrade (-h | --help)
    cargo upgrade (-V | --version)

Options:
    --all                       Upgrade all packages in the workspace.
    --precise PRECISE           Upgrade dependencies to exactly PRECISE.
    --manifest-path PATH        Path to the manifest to upgrade.
    --allow-prerelease          Include prerelease versions when fetching from crates.io (e.g.
                                '0.6.0-alpha'). Defaults to false.
    --dry-run                   Print changes to be made without making them. Defaults to false.
    -h --help                   Show this help page.
    -V --version                Show version.

This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.
";

/// Docopts input args.
#[derive(Debug, Deserialize)]
struct Args {
    /// `<dependency>...`
    arg_dependency: Vec<String>,
    /// `--precise PRECISE`
    flag_precise: Option<String>,
    /// `--manifest-path PATH`
    flag_manifest_path: Option<String>,
    /// `--all`
    flag_all: bool,
    /// `--allow-prerelease`
    flag_allow_prerelease: bool,
    /// `--dry-run`
    flag_dry_run: bool,
    /// `--version`
    flag_version: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);

        cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Failed to get workspace metadata")?
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let packages = cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Invalid manifest")?
            .packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| "Found virtual manifest, but this command requires running against an \
                           actual package in this workspace. Try adding `--all`.")?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(DesiredUpgrades(if only_update.is_empty() {
            // User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
            // dependencies.
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, _) in self.0 {
            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<String, Option<String>>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<String, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(
        self,
        precise: &Option<String>,
        allow_prerelease: bool,
    ) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else if let Some(ref v) = *precise {
                    Ok((name, v.clone()))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        arg_dependency,
        flag_precise,
        flag_manifest_path,
        flag_all,
        flag_allow_prerelease,
        flag_dry_run,
        ..
    } = args;

    let manifests = if flag_all {
        Manifests::get_all(&flag_manifest_path)
    } else {
        Manifests::get_local_one(&flag_manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(arg_dependency)?;

    let upgraded_dependencies =
        existing_dependencies.get_upgraded(&flag_precise, flag_allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, flag_dry_run)
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-upgrade version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


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

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use bindgen::cargo::Cargo;
use syn;

const STD_CRATES: &'static [&'static str] = &["std",
                                              "std_unicode",
                                              "alloc",
                                              "collections",
                                              "core",
                                              "proc_macro"];

type ParseResult = Result<(), String>;

/// Parses a single rust source file, not following `mod` or `extern crate`.
pub fn parse_src<F>(src_file: &Path,
                    items_callback: &mut F) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let src_parsed = {
        let mut s = String::new();
        let mut f = File::open(src_file).map_err(|_| format!("parsing: cannot open file `{:?}`", src_file))?;
        f.read_to_string(&mut s).map_err(|_| format!("parsing: cannot open file `{:?}`", src_file))?;
        syn::parse_crate(&s).map_err(|msg| format!("parsing:\n{}", msg))?
    };

    items_callback("", &src_parsed.items);

    Ok(())
}

/// Recursively parses a rust library starting at the root crate's directory.
///
/// Inside a crate, `mod` and `extern crate` declarations are followed
/// and parsed. To find an external crate, the parser uses the `cargo metadata`
/// command to find the location of dependencies.
pub fn parse_lib<F>(lib: Cargo,
                    include: &Option<Vec<String>>,
                    exclude: &Vec<String>,
                    expand: &Vec<String>,
                    items_callback: &mut F) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let start_crate = lib.binding_crate_name().to_owned();

    let mut context = ParseLibContext {
        lib: lib,
        include: include.clone(),
        exclude: exclude.clone(),
        expand: expand.clone(),
        cache_src: HashMap::new(),
        cache_expanded_crate: HashMap::new(),
        items_callback: items_callback,
    };

    parse_crate(&start_crate, &mut context)
}

struct ParseLibContext<F>
  where F: FnMut(&str, &Vec<syn::Item>)
{
    lib: Cargo,
    include: Option<Vec<String>>,
    exclude: Vec<String>,
    expand: Vec<String>,
    cache_src: HashMap<PathBuf, Vec<syn::Item>>,
    cache_expanded_crate: HashMap<String, Vec<syn::Item>>,

    items_callback: F,
}

fn parse_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    // Check the white list
    if let Some(ref include) = context.include {
        if !include.contains(&crate_name.to_owned()) {
            return Ok(());
        }
    }

    // Check the black list
    if STD_CRATES.contains(&crate_name) ||
       context.exclude.contains(&crate_name.to_owned()) {
        return Ok(());
    }

    // Check if we should use cargo expand
    if context.expand.contains(&crate_name.to_owned()) {
        return parse_expand_crate(crate_name, context);
    }

    // Otherwise do our normal parse
    let crate_src = context.lib.find_crate_src(crate_name);

    match crate_src {
        Some(crate_src) => {
            parse_mod(crate_name, crate_src.as_path(), context)
        },
        None => {
            // This should be an error, but is common enough to just elicit a warning
            warn!("parsing crate `{}`: can't find lib.rs with `cargo metadata`", crate_name);
            Ok(())
        },
    }
}

fn parse_expand_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let mod_parsed = {
        let owned_crate_name = crate_name.to_owned();

        if !context.cache_expanded_crate.contains_key(&owned_crate_name) {
            let s = context.lib.expand_crate(crate_name)?;
            let i = syn::parse_crate(&s).map_err(|msg| format!("parsing crate `{}`:\n{}", crate_name, msg))?;
            context.cache_expanded_crate.insert(owned_crate_name.clone(), i.items);
        }

        context.cache_expanded_crate.get(&owned_crate_name).unwrap().clone()
    };

    process_expanded_mod(crate_name, &mod_parsed, context)
}

fn process_expanded_mod<F>(crate_name: &str,
                           items: &Vec<syn::Item>,
                           context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    (context.items_callback)(crate_name, items);

    for item in items {
        match item.node {
            syn::ItemKind::Mod(ref inline_items) => {
                if let &Some(ref inline_items) = inline_items {
                    process_expanded_mod(crate_name, inline_items, context)?;
                    continue;
                }

                return Err(format!("parsing crate `{}`: external mod found in expanded source", crate_name));
            }
            syn::ItemKind::ExternCrate(_) => {
                parse_crate(&item.ident.to_string(), context)?;
            }
            _ => {}
        }
    }

    Ok(())
}

fn parse_mod<F>(crate_name: &str,
                mod_path: &Path,
                context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let mod_parsed = {
        let owned_mod_path = mod_path.to_path_buf();

        if !context.cache_src.contains_key(&owned_mod_path) {
            let mut s = String::new();
            let mut f = File::open(mod_path).map_err(|_| format!("parsing crate `{}`: cannot open file `{:?}`", crate_name, mod_path))?;
            f.read_to_string(&mut s).map_err(|_| format!("parsing crate `{}`: cannot open file `{:?}`", crate_name, mod_path))?;
            let i = syn::parse_crate(&s).map_err(|msg| format!("parsing crate `{}`:\n{}", crate_name, msg))?;
            context.cache_src.insert(owned_mod_path.clone(), i.items);
        }

        context.cache_src.get(&owned_mod_path).unwrap().clone()
    };

    let mod_dir = mod_path.parent().unwrap();

    process_mod(crate_name,
                mod_dir,
                &mod_parsed,
                context)
}

fn process_mod<F>(crate_name: &str,
                  mod_dir: &Path,
                  items: &Vec<syn::Item>,
                  context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    (context.items_callback)(crate_name, items);

    for item in items {
        match item.node {
            syn::ItemKind::Mod(ref inline_items) => {
                let next_mod_name = item.ident.to_string();

                if let &Some(ref inline_items) = inline_items {
                    process_mod(crate_name,
                                mod_dir,
                                inline_items,
                                context)?;
                    continue;
                }

                let next_mod_path1 = mod_dir.join(next_mod_name.clone() + ".rs");
                let next_mod_path2 = mod_dir.join(next_mod_name.clone()).join("mod.rs");

                if next_mod_path1.exists() {
                    parse_mod(crate_name,
                              next_mod_path1.as_path(),
                              context)?;
                } else if next_mod_path2.exists() {
                    parse_mod(crate_name,
                              next_mod_path2.as_path(),
                              context)?;
                } else {
                    // This should be an error, but is common enough to just elicit a warning
                    warn!("parsing crate `{}`: can't find mod {}`", crate_name, next_mod_name);
                }
            }
            syn::ItemKind::ExternCrate(_) => {
                parse_crate(&item.ident.to_string(), context)?;
            }
            _ => {}
        }
    }

    Ok(())
}
<commit_msg>Check config expand first before the whitelist and blacklist<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use bindgen::cargo::Cargo;
use syn;

const STD_CRATES: &'static [&'static str] = &["std",
                                              "std_unicode",
                                              "alloc",
                                              "collections",
                                              "core",
                                              "proc_macro"];

type ParseResult = Result<(), String>;

/// Parses a single rust source file, not following `mod` or `extern crate`.
pub fn parse_src<F>(src_file: &Path,
                    items_callback: &mut F) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let src_parsed = {
        let mut s = String::new();
        let mut f = File::open(src_file).map_err(|_| format!("parsing: cannot open file `{:?}`", src_file))?;
        f.read_to_string(&mut s).map_err(|_| format!("parsing: cannot open file `{:?}`", src_file))?;
        syn::parse_crate(&s).map_err(|msg| format!("parsing:\n{}", msg))?
    };

    items_callback("", &src_parsed.items);

    Ok(())
}

/// Recursively parses a rust library starting at the root crate's directory.
///
/// Inside a crate, `mod` and `extern crate` declarations are followed
/// and parsed. To find an external crate, the parser uses the `cargo metadata`
/// command to find the location of dependencies.
pub fn parse_lib<F>(lib: Cargo,
                    include: &Option<Vec<String>>,
                    exclude: &Vec<String>,
                    expand: &Vec<String>,
                    items_callback: &mut F) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let start_crate = lib.binding_crate_name().to_owned();

    let mut context = ParseLibContext {
        lib: lib,
        include: include.clone(),
        exclude: exclude.clone(),
        expand: expand.clone(),
        cache_src: HashMap::new(),
        cache_expanded_crate: HashMap::new(),
        items_callback: items_callback,
    };

    parse_crate(&start_crate, &mut context)
}

struct ParseLibContext<F>
  where F: FnMut(&str, &Vec<syn::Item>)
{
    lib: Cargo,
    include: Option<Vec<String>>,
    exclude: Vec<String>,
    expand: Vec<String>,
    cache_src: HashMap<PathBuf, Vec<syn::Item>>,
    cache_expanded_crate: HashMap<String, Vec<syn::Item>>,

    items_callback: F,
}

fn parse_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    // Check if we should use cargo expand, this skips the whitelist
    // and blacklist because expand is manually specified
    if context.expand.contains(&crate_name.to_owned()) {
        return parse_expand_crate(crate_name, context);
    }

    // Check the whitelist
    if let Some(ref include) = context.include {
        if !include.contains(&crate_name.to_owned()) {
            return Ok(());
        }
    }

    // Check the blacklist
    if STD_CRATES.contains(&crate_name) ||
       context.exclude.contains(&crate_name.to_owned()) {
        return Ok(());
    }

    // Otherwise do our normal parse
    let crate_src = context.lib.find_crate_src(crate_name);

    match crate_src {
        Some(crate_src) => {
            parse_mod(crate_name, crate_src.as_path(), context)
        },
        None => {
            // This should be an error, but is common enough to just elicit a warning
            warn!("parsing crate `{}`: can't find lib.rs with `cargo metadata`", crate_name);
            Ok(())
        },
    }
}

fn parse_expand_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let mod_parsed = {
        let owned_crate_name = crate_name.to_owned();

        if !context.cache_expanded_crate.contains_key(&owned_crate_name) {
            let s = context.lib.expand_crate(crate_name)?;
            let i = syn::parse_crate(&s).map_err(|msg| format!("parsing crate `{}`:\n{}", crate_name, msg))?;
            context.cache_expanded_crate.insert(owned_crate_name.clone(), i.items);
        }

        context.cache_expanded_crate.get(&owned_crate_name).unwrap().clone()
    };

    process_expanded_mod(crate_name, &mod_parsed, context)
}

fn process_expanded_mod<F>(crate_name: &str,
                           items: &Vec<syn::Item>,
                           context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    (context.items_callback)(crate_name, items);

    for item in items {
        match item.node {
            syn::ItemKind::Mod(ref inline_items) => {
                if let &Some(ref inline_items) = inline_items {
                    process_expanded_mod(crate_name, inline_items, context)?;
                    continue;
                }

                return Err(format!("parsing crate `{}`: external mod found in expanded source", crate_name));
            }
            syn::ItemKind::ExternCrate(_) => {
                parse_crate(&item.ident.to_string(), context)?;
            }
            _ => {}
        }
    }

    Ok(())
}

fn parse_mod<F>(crate_name: &str,
                mod_path: &Path,
                context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    let mod_parsed = {
        let owned_mod_path = mod_path.to_path_buf();

        if !context.cache_src.contains_key(&owned_mod_path) {
            let mut s = String::new();
            let mut f = File::open(mod_path).map_err(|_| format!("parsing crate `{}`: cannot open file `{:?}`", crate_name, mod_path))?;
            f.read_to_string(&mut s).map_err(|_| format!("parsing crate `{}`: cannot open file `{:?}`", crate_name, mod_path))?;
            let i = syn::parse_crate(&s).map_err(|msg| format!("parsing crate `{}`:\n{}", crate_name, msg))?;
            context.cache_src.insert(owned_mod_path.clone(), i.items);
        }

        context.cache_src.get(&owned_mod_path).unwrap().clone()
    };

    let mod_dir = mod_path.parent().unwrap();

    process_mod(crate_name,
                mod_dir,
                &mod_parsed,
                context)
}

fn process_mod<F>(crate_name: &str,
                  mod_dir: &Path,
                  items: &Vec<syn::Item>,
                  context: &mut ParseLibContext<F>) -> ParseResult
    where F: FnMut(&str, &Vec<syn::Item>)
{
    (context.items_callback)(crate_name, items);

    for item in items {
        match item.node {
            syn::ItemKind::Mod(ref inline_items) => {
                let next_mod_name = item.ident.to_string();

                if let &Some(ref inline_items) = inline_items {
                    process_mod(crate_name,
                                mod_dir,
                                inline_items,
                                context)?;
                    continue;
                }

                let next_mod_path1 = mod_dir.join(next_mod_name.clone() + ".rs");
                let next_mod_path2 = mod_dir.join(next_mod_name.clone()).join("mod.rs");

                if next_mod_path1.exists() {
                    parse_mod(crate_name,
                              next_mod_path1.as_path(),
                              context)?;
                } else if next_mod_path2.exists() {
                    parse_mod(crate_name,
                              next_mod_path2.as_path(),
                              context)?;
                } else {
                    // This should be an error, but is common enough to just elicit a warning
                    warn!("parsing crate `{}`: can't find mod {}`", crate_name, next_mod_name);
                }
            }
            syn::ItemKind::ExternCrate(_) => {
                parse_crate(&item.ident.to_string(), context)?;
            }
            _ => {}
        }
    }

    Ok(())
}
<|endoftext|>


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

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

use build_helper::output;

use Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(&path) {
                let target = path.join(&cmd);
                let mut cmd_alt = cmd.clone();
                cmd_alt.push(".exe");
                if target.is_file() || // some/path/git
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists() { // some/path/git/git.exe
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains("\"") {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .filter_map(|host| build.config.target_config.get(host))
        .any(|config| config.llvm_config.is_none());
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        cmd_finder.must_have(build.cc(*target));
        if let Some(ar) = build.ar(*target) {
            cmd_finder.must_have(ar);
        }
    }

    for host in &build.hosts {
        cmd_finder.must_have(build.cxx(*host).unwrap());

        // The msvc hosts don't use jemalloc, turn it off globally to
        // avoid packaging the dummy liballoc_jemalloc on that platform.
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_insert(Default::default());

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                                 .or_insert(Default::default());
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap_or_else(|| {
                       panic!("{:?} failed {:?}", cmd, output)
                   }).to_string()
        })
    };
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let mut stage0 = String::new();
        t!(t!(File::open(build.src.join("src/stage0.txt")))
            .read_to_string(&mut stage0));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<commit_msg>Auto merge of #50012 - Zoxc:msvc-fix, r=Mark-Simulacrum<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

use build_helper::output;

use Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(&path) {
                let target = path.join(&cmd);
                let mut cmd_alt = cmd.clone();
                cmd_alt.push(".exe");
                if target.is_file() || // some/path/git
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists() { // some/path/git/git.exe
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains("\"") {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .filter_map(|host| build.config.target_config.get(host))
        .any(|config| config.llvm_config.is_none());
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }

        // The msvc hosts don't use jemalloc, turn it off globally to
        // avoid packaging the dummy liballoc_jemalloc on that platform.
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_insert(Default::default());

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                                 .or_insert(Default::default());
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap_or_else(|| {
                       panic!("{:?} failed {:?}", cmd, output)
                   }).to_string()
        })
    };
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let mut stage0 = String::new();
        t!(t!(File::open(build.src.join("src/stage0.txt")))
            .read_to_string(&mut stage0));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<|endoftext|>


<commit_before>use cipher::block::{BlockFn, BlockCipher};
use cipher::block::feistel::Feistel;
use secret::Secret;

use typenum::consts::U16;

struct SubKey {
    // The top 16 bits are 0
    key: Secret<u64>
}

struct DesRound {
    key: SubKey
}

impl BlockFn for DesRound {
    type Block = Secret<u32>;
    fn encrypt(&self, block: Secret<u32>) -> Secret<u32> {
        permute(substitute(expand(block) ^ self.key.key))
    }
}

pub struct Des {
    inner: Feistel<DesRound, U16>
}

impl BlockFn for Des {
    type Block = Secret<u64>;
    fn encrypt(&self, block: Secret<u64>) -> Secret<u64> {
        final_permute(self.inner.encrypt(initial_permute(block)))
    }
}

impl BlockCipher for Des {
    fn decrypt(&self, block: Secret<u64>) -> Secret<u64> {
        final_permute(self.inner.decrypt(initial_permute(block)))
    }
}

// See FIPS Publication 46-3, Appendix 1
const INITAL_PERMUTATION: [u8; 64] = [
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6,
    64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9,  1,
    59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5,
    63, 55, 47, 39, 31, 23, 15, 7
];

// Inverse of final_permute
fn initial_permute(block: Secret<u64>) -> (Secret<u32>, Secret<u32>) {
    unimplemented!()
}

// See FIPS Publication 46-3, Appendix 1
const FINAL_PERMUTATION: [u8; 64] = [
    40, 8, 48, 16, 56, 24, 64, 32,
    39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30,
	37, 5, 45, 13, 53, 21, 61, 29,
	36, 4, 44, 12, 52, 20, 60, 28,
	35, 3, 43, 11, 51, 19, 59, 27,
	34, 2, 42, 10, 50, 18, 58, 26,
	33, 1, 41, 9,  49, 17, 57, 25
];

// Inverse of initial_permute
fn final_permute(block: (Secret<u32>, Secret<u32>)) -> Secret<u64> {
    unimplemented!()
}

// See FIPS Publication 46-3, Appendix 1
const EXPANSION_PERMUTATION: [u8; 48] = [
	32, 1,  2,  3,  4,  5,
	4,  5,  6,  7,  8,  9,
	8,  9,  10, 11, 12, 13,
	12, 13, 14, 15, 16, 17,
	16, 17, 18, 19, 20, 21,
	20, 21, 22, 23, 24, 25,
	24, 25, 26, 27, 28, 29,
	28, 29, 30, 31, 32, 1
];

// Returns 48 bits
fn expand(half_block: Secret<u32>) -> Secret<u64> {
    unimplemented!()
}

// Takes 48 bits
fn substitute(block: Secret<u64>) -> Secret<u32> {
    unimplemented!()
}

// See FIPS Publication 46-3, Appendix 1
const ROUND_PERMUTATION: [u8; 32] = [
	16, 7,  20, 21, 29, 12, 28, 17,
	1,  15, 23, 26, 5,  18, 31, 10,
	2,  8,  24, 14, 32, 27, 3,  9,
	19, 13, 30, 6,  22, 11, 4,  25
];

fn permute(block: Secret<u32>) -> Secret<u32> {
    unimplemented!()
}
<commit_msg>Implement the permutations for DES<commit_after>use cipher::block::{BlockFn, BlockCipher};
use cipher::block::feistel::Feistel;
use secret::Secret;
use truncate::Truncate;

use typenum::consts::U16;

struct SubKey {
    // The top 16 bits are 0
    key: Secret<u64>
}

struct DesRound {
    key: SubKey
}

impl BlockFn for DesRound {
    type Block = Secret<u32>;
    fn encrypt(&self, block: Secret<u32>) -> Secret<u32> {
        permute(substitute(expand(block) ^ self.key.key))
    }
}

pub struct Des {
    inner: Feistel<DesRound, U16>
}

impl BlockFn for Des {
    type Block = Secret<u64>;
    fn encrypt(&self, block: Secret<u64>) -> Secret<u64> {
        final_permute(self.inner.encrypt(initial_permute(block)))
    }
}

impl BlockCipher for Des {
    fn decrypt(&self, block: Secret<u64>) -> Secret<u64> {
        final_permute(self.inner.decrypt(initial_permute(block)))
    }
}

fn run_permutation(perm: &[u8], val: Secret<u64>) -> Secret<u64> {
    let mut out = Secret::new(0);
    for (i, src) in perm.iter().enumerate() {
        out |= ((val >> *src as usize) & 1) << i;
    }
    out
}

// See FIPS Publication 46-3, Appendix 1
const INITIAL_PERMUTATION: [u8; 64] = [
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6,
    64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9,  1,
    59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5,
    63, 55, 47, 39, 31, 23, 15, 7
];

// Inverse of final_permute
fn initial_permute(block: Secret<u64>) -> (Secret<u32>, Secret<u32>) {
    let ret = run_permutation(&INITIAL_PERMUTATION, block);
    (ret.truncate(), (ret >> 32).truncate())
}

// See FIPS Publication 46-3, Appendix 1
const FINAL_PERMUTATION: [u8; 64] = [
    40, 8, 48, 16, 56, 24, 64, 32,
    39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30,
	37, 5, 45, 13, 53, 21, 61, 29,
	36, 4, 44, 12, 52, 20, 60, 28,
	35, 3, 43, 11, 51, 19, 59, 27,
	34, 2, 42, 10, 50, 18, 58, 26,
	33, 1, 41, 9,  49, 17, 57, 25
];

// Inverse of initial_permute
fn final_permute(block: (Secret<u32>, Secret<u32>)) -> Secret<u64> {
    let joined = Secret::<u64>::from(block.0) | (Secret::<u64>::from(block.1) << 32);
    run_permutation(&FINAL_PERMUTATION, joined)
}

// See FIPS Publication 46-3, Appendix 1
const EXPANSION_PERMUTATION: [u8; 48] = [
	32, 1,  2,  3,  4,  5,
	4,  5,  6,  7,  8,  9,
	8,  9,  10, 11, 12, 13,
	12, 13, 14, 15, 16, 17,
	16, 17, 18, 19, 20, 21,
	20, 21, 22, 23, 24, 25,
	24, 25, 26, 27, 28, 29,
	28, 29, 30, 31, 32, 1
];

// Returns 48 bits
fn expand(half_block: Secret<u32>) -> Secret<u64> {
    run_permutation(&EXPANSION_PERMUTATION, Secret::<u64>::from(half_block))
}

// Takes 48 bits
fn substitute(block: Secret<u64>) -> Secret<u32> {
    unimplemented!()
}

// See FIPS Publication 46-3, Appendix 1
const ROUND_PERMUTATION: [u8; 32] = [
	16, 7,  20, 21, 29, 12, 28, 17,
	1,  15, 23, 26, 5,  18, 31, 10,
	2,  8,  24, 14, 32, 27, 3,  9,
	19, 13, 30, 6,  22, 11, 4,  25
];

fn permute(block: Secret<u32>) -> Secret<u32> {
    run_permutation(&ROUND_PERMUTATION, Secret::<u64>::from(block)).truncate()
}
<|endoftext|>