<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 {OpaqueStyleAndLayoutData, TrustedNodeAddress, PendingImage};
use app_units::Au;
use euclid::{Point2D, Rect};
use gfx_traits::Epoch;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use metrics::PaintTimeMetrics;
use msg::constellation_msg::PipelineId;
use net_traits::image_cache::ImageCache;
use profile_traits::mem::ReportsChan;
use rpc::LayoutRPC;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData};
use script_traits::Painter;
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
use style::context::QuirksMode;
use style::properties::PropertyId;
use style::selector_parser::PseudoElement;
use style::stylesheets::Stylesheet;

/// Asynchronous messages that script can send to layout.
pub enum Msg {
    /// Adds the given stylesheet to the document. The second stylesheet is the
    /// insertion point (if it exists, the sheet needs to be inserted before
    /// it).
    AddStylesheet(ServoArc<Stylesheet>, Option<ServoArc<Stylesheet>>),

    /// Removes a stylesheet from the document.
    RemoveStylesheet(ServoArc<Stylesheet>),

    /// Change the quirks mode.
    SetQuirksMode(QuirksMode),

    /// Requests a reflow.
    Reflow(ScriptReflow),

    /// Get an RPC interface.
    GetRPC(Sender<Box<LayoutRPC + Send>>),

    /// Requests that the layout thread render the next frame of all animations.
    TickAnimations,

    /// Updates layout's timer for animation testing from script.
    ///
    /// The inner field is the number of *milliseconds* to advance, and the bool
    /// field is whether animations should be force-ticked.
    AdvanceClockMs(i32, bool),

    /// Destroys layout data associated with a DOM node.
    ///
    /// TODO(pcwalton): Maybe think about batching to avoid message traffic.
    ReapStyleAndLayoutData(OpaqueStyleAndLayoutData),

    /// Requests that the layout thread measure its memory usage. The resulting reports are sent back
    /// via the supplied channel.
    CollectReports(ReportsChan),

    /// Requests that the layout thread enter a quiescent state in which no more messages are
    /// accepted except `ExitMsg`. A response message will be sent on the supplied channel when
    /// this happens.
    PrepareToExit(Sender<()>),

    /// Requests that the layout thread immediately shut down. There must be no more nodes left after
    /// this, or layout will crash.
    ExitNow,

    /// Get the last epoch counter for this layout thread.
    GetCurrentEpoch(IpcSender<Epoch>),

    /// Asks the layout thread whether any Web fonts have yet to load (if true, loads are pending;
    /// false otherwise).
    GetWebFontLoadState(IpcSender<bool>),

    /// Creates a new layout thread.
    ///
    /// This basically exists to keep the script-layout dependency one-way.
    CreateLayoutThread(NewLayoutThreadInfo),

    /// Set the final Url.
    SetFinalUrl(ServoUrl),

    /// Tells layout about the new scrolling offsets of each scrollable stacking context.
    SetScrollStates(Vec<ScrollState>),

    /// Tells layout about a single new scrolling offset from the script. The rest will
    /// remain untouched and layout won't forward this back to script.
    UpdateScrollStateFromScript(ScrollState),

    /// Tells layout that script has added some paint worklet modules.
    RegisterPaint(Atom, Vec<Atom>, Box<Painter>),

    /// Send to layout the precise time when the navigation started.
    SetNavigationStart(f64),
}

/// Any query to perform with this reflow.
#[derive(Debug, PartialEq)]
pub enum ReflowGoal {
    Full,
    TickAnimations,
    ContentBoxQuery(TrustedNodeAddress),
    ContentBoxesQuery(TrustedNodeAddress),
    NodeOverflowQuery(TrustedNodeAddress),
    HitTestQuery(Point2D<f32>, bool),
    NodeScrollRootIdQuery(TrustedNodeAddress),
    NodeGeometryQuery(TrustedNodeAddress),
    NodeScrollGeometryQuery(TrustedNodeAddress),
    ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId),
    OffsetParentQuery(TrustedNodeAddress),
    MarginStyleQuery(TrustedNodeAddress),
    TextIndexQuery(TrustedNodeAddress, i32, i32),
    NodesFromPoint(Point2D<f32>),
}

impl ReflowGoal {
    /// Returns true if the given ReflowQuery needs a full, up-to-date display list to
    /// be present or false if it only needs stacking-relative positions.
    pub fn needs_display_list(&self) -> bool {
        match *self {
            ReflowGoal::NodesFromPoint(..) | ReflowGoal::HitTestQuery(..) |
            ReflowGoal::TextIndexQuery(..) | ReflowGoal::Full => true,
            ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
            ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
            ReflowGoal::NodeOverflowQuery(_) | ReflowGoal::NodeScrollRootIdQuery(_) |
            ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) |
            ReflowGoal::MarginStyleQuery(_) |  ReflowGoal::TickAnimations => false,
        }
    }

    /// Returns true if the given ReflowQuery needs its display list send to WebRender or
    /// false if a layout_thread display list is sufficient.
    pub fn needs_display(&self) -> bool {
        match *self {
            ReflowGoal::MarginStyleQuery(_)  | ReflowGoal::TextIndexQuery(..) |
            ReflowGoal::HitTestQuery(..) | ReflowGoal::ContentBoxQuery(_) |
            ReflowGoal::ContentBoxesQuery(_) | ReflowGoal::NodeGeometryQuery(_) |
            ReflowGoal::NodeScrollGeometryQuery(_) | ReflowGoal::NodeOverflowQuery(_) |
            ReflowGoal::NodeScrollRootIdQuery(_) | ReflowGoal::ResolvedStyleQuery(..) |
            ReflowGoal::OffsetParentQuery(_) | ReflowGoal::NodesFromPoint(..) => false,
            ReflowGoal::Full | ReflowGoal::TickAnimations => true,
        }
    }
}

/// Information needed for a reflow.
pub struct Reflow {
    ///  A clipping rectangle for the page, an enlarged rectangle containing the viewport.
    pub page_clip_rect: Rect<Au>,
}

/// Information derived from a layout pass that needs to be returned to the script thread.
#[derive(Default)]
pub struct ReflowComplete {
    /// The list of images that were encountered that are in progress.
    pub pending_images: Vec<PendingImage>,
    /// The list of nodes that initiated a CSS transition.
    pub newly_transitioning_nodes: Vec<UntrustedNodeAddress>,
}

/// Information needed for a script-initiated reflow.
pub struct ScriptReflow {
    /// General reflow data.
    pub reflow_info: Reflow,
    /// The document node.
    pub document: TrustedNodeAddress,
    /// Whether the document's stylesheets have changed since the last script reflow.
    pub stylesheets_changed: bool,
    /// The current window size.
    pub window_size: WindowSizeData,
    /// The channel that we send a notification to.
    pub script_join_chan: Sender<ReflowComplete>,
    /// The goal of this reflow.
    pub reflow_goal: ReflowGoal,
    /// The number of objects in the dom #10110
    pub dom_count: u32,
}

pub struct NewLayoutThreadInfo {
    pub id: PipelineId,
    pub url: ServoUrl,
    pub is_parent: bool,
    pub layout_pair: (Sender<Msg>, Receiver<Msg>),
    pub pipeline_port: IpcReceiver<LayoutControlMsg>,
    pub constellation_chan: IpcSender<ConstellationMsg>,
    pub script_chan: IpcSender<ConstellationControlMsg>,
    pub image_cache: Arc<ImageCache>,
    pub content_process_shutdown_chan: Option<IpcSender<()>>,
    pub layout_threads: usize,
    pub paint_time_metrics: PaintTimeMetrics,
}
<commit_msg>Auto merge of #18725 - mrobinson:tick-animation-display-list, r=jdm<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 {OpaqueStyleAndLayoutData, TrustedNodeAddress, PendingImage};
use app_units::Au;
use euclid::{Point2D, Rect};
use gfx_traits::Epoch;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use metrics::PaintTimeMetrics;
use msg::constellation_msg::PipelineId;
use net_traits::image_cache::ImageCache;
use profile_traits::mem::ReportsChan;
use rpc::LayoutRPC;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData};
use script_traits::Painter;
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
use style::context::QuirksMode;
use style::properties::PropertyId;
use style::selector_parser::PseudoElement;
use style::stylesheets::Stylesheet;

/// Asynchronous messages that script can send to layout.
pub enum Msg {
    /// Adds the given stylesheet to the document. The second stylesheet is the
    /// insertion point (if it exists, the sheet needs to be inserted before
    /// it).
    AddStylesheet(ServoArc<Stylesheet>, Option<ServoArc<Stylesheet>>),

    /// Removes a stylesheet from the document.
    RemoveStylesheet(ServoArc<Stylesheet>),

    /// Change the quirks mode.
    SetQuirksMode(QuirksMode),

    /// Requests a reflow.
    Reflow(ScriptReflow),

    /// Get an RPC interface.
    GetRPC(Sender<Box<LayoutRPC + Send>>),

    /// Requests that the layout thread render the next frame of all animations.
    TickAnimations,

    /// Updates layout's timer for animation testing from script.
    ///
    /// The inner field is the number of *milliseconds* to advance, and the bool
    /// field is whether animations should be force-ticked.
    AdvanceClockMs(i32, bool),

    /// Destroys layout data associated with a DOM node.
    ///
    /// TODO(pcwalton): Maybe think about batching to avoid message traffic.
    ReapStyleAndLayoutData(OpaqueStyleAndLayoutData),

    /// Requests that the layout thread measure its memory usage. The resulting reports are sent back
    /// via the supplied channel.
    CollectReports(ReportsChan),

    /// Requests that the layout thread enter a quiescent state in which no more messages are
    /// accepted except `ExitMsg`. A response message will be sent on the supplied channel when
    /// this happens.
    PrepareToExit(Sender<()>),

    /// Requests that the layout thread immediately shut down. There must be no more nodes left after
    /// this, or layout will crash.
    ExitNow,

    /// Get the last epoch counter for this layout thread.
    GetCurrentEpoch(IpcSender<Epoch>),

    /// Asks the layout thread whether any Web fonts have yet to load (if true, loads are pending;
    /// false otherwise).
    GetWebFontLoadState(IpcSender<bool>),

    /// Creates a new layout thread.
    ///
    /// This basically exists to keep the script-layout dependency one-way.
    CreateLayoutThread(NewLayoutThreadInfo),

    /// Set the final Url.
    SetFinalUrl(ServoUrl),

    /// Tells layout about the new scrolling offsets of each scrollable stacking context.
    SetScrollStates(Vec<ScrollState>),

    /// Tells layout about a single new scrolling offset from the script. The rest will
    /// remain untouched and layout won't forward this back to script.
    UpdateScrollStateFromScript(ScrollState),

    /// Tells layout that script has added some paint worklet modules.
    RegisterPaint(Atom, Vec<Atom>, Box<Painter>),

    /// Send to layout the precise time when the navigation started.
    SetNavigationStart(f64),
}

/// Any query to perform with this reflow.
#[derive(Debug, PartialEq)]
pub enum ReflowGoal {
    Full,
    TickAnimations,
    ContentBoxQuery(TrustedNodeAddress),
    ContentBoxesQuery(TrustedNodeAddress),
    NodeOverflowQuery(TrustedNodeAddress),
    HitTestQuery(Point2D<f32>, bool),
    NodeScrollRootIdQuery(TrustedNodeAddress),
    NodeGeometryQuery(TrustedNodeAddress),
    NodeScrollGeometryQuery(TrustedNodeAddress),
    ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId),
    OffsetParentQuery(TrustedNodeAddress),
    MarginStyleQuery(TrustedNodeAddress),
    TextIndexQuery(TrustedNodeAddress, i32, i32),
    NodesFromPoint(Point2D<f32>),
}

impl ReflowGoal {
    /// Returns true if the given ReflowQuery needs a full, up-to-date display list to
    /// be present or false if it only needs stacking-relative positions.
    pub fn needs_display_list(&self) -> bool {
        match *self {
            ReflowGoal::NodesFromPoint(..) | ReflowGoal::HitTestQuery(..) |
            ReflowGoal::TextIndexQuery(..) | ReflowGoal::TickAnimations |
            ReflowGoal::Full => true,
            ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
            ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
            ReflowGoal::NodeOverflowQuery(_) | ReflowGoal::NodeScrollRootIdQuery(_) |
            ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) |
            ReflowGoal::MarginStyleQuery(_)  => false,
        }
    }

    /// Returns true if the given ReflowQuery needs its display list send to WebRender or
    /// false if a layout_thread display list is sufficient.
    pub fn needs_display(&self) -> bool {
        match *self {
            ReflowGoal::MarginStyleQuery(_)  | ReflowGoal::TextIndexQuery(..) |
            ReflowGoal::HitTestQuery(..) | ReflowGoal::ContentBoxQuery(_) |
            ReflowGoal::ContentBoxesQuery(_) | ReflowGoal::NodeGeometryQuery(_) |
            ReflowGoal::NodeScrollGeometryQuery(_) | ReflowGoal::NodeOverflowQuery(_) |
            ReflowGoal::NodeScrollRootIdQuery(_) | ReflowGoal::ResolvedStyleQuery(..) |
            ReflowGoal::OffsetParentQuery(_) | ReflowGoal::NodesFromPoint(..) => false,
            ReflowGoal::Full | ReflowGoal::TickAnimations => true,
        }
    }
}

/// Information needed for a reflow.
pub struct Reflow {
    ///  A clipping rectangle for the page, an enlarged rectangle containing the viewport.
    pub page_clip_rect: Rect<Au>,
}

/// Information derived from a layout pass that needs to be returned to the script thread.
#[derive(Default)]
pub struct ReflowComplete {
    /// The list of images that were encountered that are in progress.
    pub pending_images: Vec<PendingImage>,
    /// The list of nodes that initiated a CSS transition.
    pub newly_transitioning_nodes: Vec<UntrustedNodeAddress>,
}

/// Information needed for a script-initiated reflow.
pub struct ScriptReflow {
    /// General reflow data.
    pub reflow_info: Reflow,
    /// The document node.
    pub document: TrustedNodeAddress,
    /// Whether the document's stylesheets have changed since the last script reflow.
    pub stylesheets_changed: bool,
    /// The current window size.
    pub window_size: WindowSizeData,
    /// The channel that we send a notification to.
    pub script_join_chan: Sender<ReflowComplete>,
    /// The goal of this reflow.
    pub reflow_goal: ReflowGoal,
    /// The number of objects in the dom #10110
    pub dom_count: u32,
}

pub struct NewLayoutThreadInfo {
    pub id: PipelineId,
    pub url: ServoUrl,
    pub is_parent: bool,
    pub layout_pair: (Sender<Msg>, Receiver<Msg>),
    pub pipeline_port: IpcReceiver<LayoutControlMsg>,
    pub constellation_chan: IpcSender<ConstellationMsg>,
    pub script_chan: IpcSender<ConstellationControlMsg>,
    pub image_cache: Arc<ImageCache>,
    pub content_process_shutdown_chan: Option<IpcSender<()>>,
    pub layout_threads: usize,
    pub paint_time_metrics: PaintTimeMetrics,
}
<|endoftext|>


<commit_before>extern crate rppal;

use std::env;
use std::ffi::OsString;
use rppal::gpio::{GPIO,Mode,Level};

const LAST_PIN_NUMBER: u8 = 27;
const HELP_CMD_STR: &'static str = "help";
const SET_CMD_STR: &'static str = "set";
const GET_CMD_STR: &'static str = "get";
const HIGH_PIN_STATE_STR: &'static str = "high";
const LOW_PIN_STATE_STR: &'static str = "low";
const ALL_PINS_STR: &'static str = "all";
const HELP_EXAMPLE_STR: &'static str = "sudo pi3gpio help";

fn main() {
	handle_cmd ( env::args_os() );
}

fn handle_cmd (mut cmd: env::ArgsOs) {
	match cmd.nth(1) {
		Some (action) => {
			if action == OsString::from(HELP_CMD_STR) {
				print_help_text ();
			}
			else if action == OsString::from(SET_CMD_STR) {
				set_pins (cmd);
			}
			else if action == OsString::from(GET_CMD_STR) {
				read_pins (cmd);
			}
			else {
				panic! ("Unknown command {:?}! \nFor help run \"{}\"", action, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("No command found! \nFor help run \"{}\"", HELP_EXAMPLE_STR ),
	}
}

fn print_help_text () {
	println! ("SYNTAX: sudo pi3gpio command [state] [pins]");
	println! ("	command: ");
	println! ("		{}	prints the help text", HELP_CMD_STR );
	println! ("		{}	sets the value of the indicated pins to the indicated value", SET_CMD_STR );
	println! ("		{}	prints the state of the indicated pins", GET_CMD_STR );
	println! ("	state: ");
	println! ("		{}	logical 1 for the indicated pins, equivalent voltage 3.3[V]", HIGH_PIN_STATE_STR );
	println! ("		{}	logical 0 for the indicated pins, equivalent voltage 0[V]", LOW_PIN_STATE_STR );
	println! ("	pins: ");
	println! ("		{}	BCM pins between 0 and {}", ALL_PINS_STR, LAST_PIN_NUMBER );
	println! ("Examples:");
	println! ("	sudo pi3gpio help ");
	println! ("	sudo pi3gpio get all");
	println! ("	sudo pi3gpio get 4");
	println! ("	sudo pi3gpio get 10 11");
	println! ("	sudo pi3gpio set low all");
	println! ("	sudo pi3gpio set high 12");
	println! ("	sudo pi3gpio set low 2 5 7");
}

trait ReadState{
	fn read_state (self, gpio: &mut GPIO);
}

impl ReadState for OsString {
	fn read_state (self, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => read_pin ( gpio, pin ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn read_all_pins ( gpio: &mut GPIO ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		read_pin ( gpio, pin );
	}
}

fn read_pin ( gpio: &mut GPIO, pin: u8) {
	gpio.set_mode( pin, Mode::Input );
	match gpio.read(pin) {
		Ok(state) =>	println! ("Pin {} = {:?}", pin, state ),
		Err (_) => println! ("Could not read state of pin {}",pin),
	}
}

fn read_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				read_all_pins ( &mut gpio );
				return;
			}
			else {
				pin_as_os_string.read_state ( &mut gpio );
			}
		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.read_state ( &mut gpio );
	}

}

trait ToU8 {
	fn to_u8 (self) -> Result<u8, &'static str >;
}

impl ToU8 for OsString {
	fn to_u8 (self) -> Result<u8, &'static str> {
		match self.into_string() {
			Ok(x) => match x.parse::<u8>() {
				Ok (y) => return Ok (y),
				Err(_) => return Err("String indicating pin number could not be converted to u8!" ),
			},
			Err(_) => return Err("OsString indicating pin number could not be converted to String!" ),
		}
	}
}

fn initiate_gpio_handle () -> GPIO {
    let gpio: GPIO;
    match GPIO::new(){
	    Ok (x) => gpio = x,
	    Err (e) => panic! ("Could not access GPIO memory! {}",e),
    }

    gpio
}

fn get_pin_state ( argument: Option<OsString>  ) -> Level {
	let mut pin_state = Level::Low;
	match argument {
		Some (state) => {
			if state == OsString::from(HIGH_PIN_STATE_STR) {
				pin_state = Level::High;
			}
			else if state != OsString::from(LOW_PIN_STATE_STR) {
				panic! ("State {:?} is invalid! \nFor help run \"{}\"", state, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("State not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

    pin_state
}

trait SetState{
	fn set_state (self, pin_state: Level ,gpio: &mut GPIO);
}

impl SetState for OsString {
	fn set_state (self, pin_state: Level, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => set_pin ( gpio, pin, pin_state ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn set_all_pins ( gpio: &mut GPIO, pin_state: Level ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		set_pin ( gpio, pin, pin_state );
	}
}

fn set_pin ( gpio: &mut GPIO, pin: u8, pin_state: Level ) {
	println! ("Set pin {} to {:?}", pin, pin_state);
	gpio.set_mode( pin, Mode::Output );
	gpio.write ( pin, pin_state );
}

fn set_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();
	gpio.set_clear_on_drop ( false );

	let pin_state = get_pin_state( cmd.nth(0) );

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				set_all_pins ( &mut gpio, pin_state );
				return;
			}
			else {
				pin_as_os_string.set_state( pin_state, &mut gpio );
			}

		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.set_state( pin_state, &mut gpio );
	}
}
<commit_msg>Update main.rs<commit_after>// Copyright 2017 Viorel Bota
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

extern crate rppal;

use std::env;
use std::ffi::OsString;
use rppal::gpio::{GPIO,Mode,Level};

const LAST_PIN_NUMBER: u8 = 27;
const HELP_CMD_STR: &'static str = "help";
const SET_CMD_STR: &'static str = "set";
const GET_CMD_STR: &'static str = "get";
const HIGH_PIN_STATE_STR: &'static str = "high";
const LOW_PIN_STATE_STR: &'static str = "low";
const ALL_PINS_STR: &'static str = "all";
const HELP_EXAMPLE_STR: &'static str = "sudo pi3gpio help";

fn main() {
	handle_cmd ( env::args_os() );
}

fn handle_cmd (mut cmd: env::ArgsOs) {
	match cmd.nth(1) {
		Some (action) => {
			if action == OsString::from(HELP_CMD_STR) {
				print_help_text ();
			}
			else if action == OsString::from(SET_CMD_STR) {
				set_pins (cmd);
			}
			else if action == OsString::from(GET_CMD_STR) {
				read_pins (cmd);
			}
			else {
				panic! ("Unknown command {:?}! \nFor help run \"{}\"", action, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("No command found! \nFor help run \"{}\"", HELP_EXAMPLE_STR ),
	}
}

fn print_help_text () {
	println! ("SYNTAX: sudo pi3gpio command [state] [pins]");
	println! ("	command: ");
	println! ("		{}	prints the help text", HELP_CMD_STR );
	println! ("		{}	sets the value of the indicated pins to the indicated value", SET_CMD_STR );
	println! ("		{}	prints the state of the indicated pins", GET_CMD_STR );
	println! ("	state: ");
	println! ("		{}	logical 1 for the indicated pins, equivalent voltage 3.3[V]", HIGH_PIN_STATE_STR );
	println! ("		{}	logical 0 for the indicated pins, equivalent voltage 0[V]", LOW_PIN_STATE_STR );
	println! ("	pins: ");
	println! ("		{}	BCM pins between 0 and {}", ALL_PINS_STR, LAST_PIN_NUMBER );
	println! ("Examples:");
	println! ("	sudo pi3gpio help ");
	println! ("	sudo pi3gpio get all");
	println! ("	sudo pi3gpio get 4");
	println! ("	sudo pi3gpio get 10 11");
	println! ("	sudo pi3gpio set low all");
	println! ("	sudo pi3gpio set high 12");
	println! ("	sudo pi3gpio set low 2 5 7");
}

trait ReadState{
	fn read_state (self, gpio: &mut GPIO);
}

impl ReadState for OsString {
	fn read_state (self, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => read_pin ( gpio, pin ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn read_all_pins ( gpio: &mut GPIO ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		read_pin ( gpio, pin );
	}
}

fn read_pin ( gpio: &mut GPIO, pin: u8) {
	gpio.set_mode( pin, Mode::Input );
	match gpio.read(pin) {
		Ok(state) =>	println! ("Pin {} = {:?}", pin, state ),
		Err (_) => println! ("Could not read state of pin {}",pin),
	}
}

fn read_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				read_all_pins ( &mut gpio );
				return;
			}
			else {
				pin_as_os_string.read_state ( &mut gpio );
			}
		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.read_state ( &mut gpio );
	}

}

trait ToU8 {
	fn to_u8 (self) -> Result<u8, &'static str >;
}

impl ToU8 for OsString {
	fn to_u8 (self) -> Result<u8, &'static str> {
		match self.into_string() {
			Ok(x) => match x.parse::<u8>() {
				Ok (y) => return Ok (y),
				Err(_) => return Err("String indicating pin number could not be converted to u8!" ),
			},
			Err(_) => return Err("OsString indicating pin number could not be converted to String!" ),
		}
	}
}

fn initiate_gpio_handle () -> GPIO {
    let gpio: GPIO;
    match GPIO::new(){
	    Ok (x) => gpio = x,
	    Err (e) => panic! ("Could not access GPIO memory! {}",e),
    }

    gpio
}

fn get_pin_state ( argument: Option<OsString>  ) -> Level {
	let mut pin_state = Level::Low;
	match argument {
		Some (state) => {
			if state == OsString::from(HIGH_PIN_STATE_STR) {
				pin_state = Level::High;
			}
			else if state != OsString::from(LOW_PIN_STATE_STR) {
				panic! ("State {:?} is invalid! \nFor help run \"{}\"", state, HELP_EXAMPLE_STR );
			}
		},
		None => panic! ("State not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

    pin_state
}

trait SetState{
	fn set_state (self, pin_state: Level ,gpio: &mut GPIO);
}

impl SetState for OsString {
	fn set_state (self, pin_state: Level, gpio: &mut GPIO) {
		match self.to_u8() {
			Ok (pin) => set_pin ( gpio, pin, pin_state ),
			Err (e) => {
				panic! ("{} \nFor help run \"{}\"", e,  HELP_EXAMPLE_STR );
			},
		}
	}
}

fn set_all_pins ( gpio: &mut GPIO, pin_state: Level ) {
	for pin in 0..(LAST_PIN_NUMBER+1) {
		set_pin ( gpio, pin, pin_state );
	}
}

fn set_pin ( gpio: &mut GPIO, pin: u8, pin_state: Level ) {
	println! ("Set pin {} to {:?}", pin, pin_state);
	gpio.set_mode( pin, Mode::Output );
	gpio.write ( pin, pin_state );
}

fn set_pins (mut cmd: env::ArgsOs) {
	let mut gpio = initiate_gpio_handle();
	gpio.set_clear_on_drop ( false );

	let pin_state = get_pin_state( cmd.nth(0) );

	match cmd.nth(0) {
		Some (pin_as_os_string) => {
			if pin_as_os_string == OsString::from(ALL_PINS_STR) {
				set_all_pins ( &mut gpio, pin_state );
				return;
			}
			else {
				pin_as_os_string.set_state( pin_state, &mut gpio );
			}

		}
		None => panic! ("Pin not found! \nFor help run \"{}\"",  HELP_EXAMPLE_STR ),
	}

	for argument in cmd {
		argument.set_state( pin_state, &mut gpio );
	}
}

// For library "rppal" version "0.1.2" the following LICENSE (MIT) applyes:
// "
//   Copyright (c) 2017 Rene van der Meer
//
//   Permission is hereby granted, free of charge, to any person obtaining a
//   copy of this software and associated documentation files (the "Software"),
//   to deal in the Software without restriction, including without limitation
//   the rights to use, copy, modify, merge, publish, distribute, sublicense,
//   and/or sell copies of the Software, and to permit persons to whom the
//   Software is furnished to do so, subject to the following conditions:
//
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
// "

// For the "std" rust library the following LINCESE (MIT) applyes:
// "
//   Copyright (c) 2010 The Rust Project Developers
//
//   Permission is hereby granted, free of charge, to any
//   person obtaining a copy of this software and associated
//   documentation files (the "Software"), to deal in the
//   Software without restriction, including without
//   limitation the rights to use, copy, modify, merge,
//   publish, distribute, sublicense, and/or sell copies of
//   the Software, and to permit persons to whom the Software
//   is furnished to do so, subject to the following
//   conditions:
//
//   The above copyright notice and this permission notice
//   shall be included in all copies or substantial portions
//   of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
//   ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//   TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
//   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
//   SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
//   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
//   IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//   DEALINGS IN THE SOFTWARE.
// "
<|endoftext|>


<commit_before>// !
// Entity component system
//

#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::default::Default;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{hash_map, HashMap, HashSet};
use std::collections::hash_set;

/// Handle for an entity in the entity component system.
///
/// The internal value is the unique identifier for the entity. No two
/// entities should get the same UID during the lifetime of the ECS.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Entity(pub usize);

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(Serialize, Deserialize)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<Entity, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData { data: HashMap::new() }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, e: Entity, comp: C) {
        self.data.insert(e, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, e: Entity) -> bool {
        self.data.contains_key(&e)
    }

    /// Get a reference to a component only if it exists for this entity.
    pub fn get(&self, e: Entity) -> Option<&C> {
        self.data.get(&e)
    }

    /// Get a mutable reference to a component only if it exists for this entity.
    pub fn get_mut(&mut self, e: Entity) -> Option<&mut C> {
        self.data.get_mut(&e)
    }

    /// Iterate entity-component pairs for this component.
    pub fn iter(&self) -> hash_map::Iter<Entity, C> {
        self.data.iter()
    }

    /// Iterate mutable entity-component pairs for this component.
    pub fn iter_mut(&mut self) -> hash_map::IterMut<Entity, C> {
        self.data.iter_mut()
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, e: Entity) -> &'a C {
        self.data.get(&e).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, e: Entity) -> &'a mut C {
        self.data.get_mut(&e).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, e: Entity) {
        self.data.remove(&e);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F) where F: FnMut(&mut AnyComponent);
}

#[derive(Serialize, Deserialize)]
pub struct Ecs<ST> {
    next_uid: usize,
    active: HashSet<Entity>,
    store: ST,
}

impl<ST: Default + Store> Ecs<ST> {
    pub fn new() -> Ecs<ST> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity(next);
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<ST> Deref for Ecs<ST> {
    type Target = ST;

    fn deref(&self) -> &ST {
        &self.store
    }
}

impl<ST> DerefMut for Ecs<ST> {
    fn deref_mut(&mut self) -> &mut ST {
        &mut self.store
    }
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

#[derive(Serialize, Deserialize)]
        pub struct _ComponentStore {
            $(pub $compname: $crate::ComponentData<$comptype>),+
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: $crate::ComponentData::new()),+
                }
            }
        }

        impl $crate::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut $crate::AnyComponent)
            {
                $(f(&mut self.$compname as &mut $crate::AnyComponent);)+
            }
        }

#[allow(dead_code)]
        pub fn matches_mask(ecs: &$crate::Ecs<_ComponentStore>, e: $crate::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity);

            /// Add a clone of the component to a loadout struct.
            fn add_to_loadout(self, loadout: &mut Loadout);
        }

        $(impl Component for $comptype {
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity) {
                ecs.$compname.insert(e, self.clone());
            }

            fn add_to_loadout(self, loadout: &mut Loadout) {
                loadout.$compname = Some(self);
            }
        })+

        pub type Ecs = $crate::Ecs<_ComponentStore>;

        /// A straightforward representation for the complete data of an
        /// entity.
        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Loadout {
            $(pub $compname: Option<$comptype>),+
        }

        impl ::std::default::Default for Loadout {
            fn default() -> Loadout {
                Loadout {
                    $($compname: None),+
                }
            }
        }

#[allow(dead_code)]
        impl Loadout {
            /// Create a new blank loadout.
            pub fn new() -> Loadout { Default::default() }

            /// Get the loadout that corresponds to an existing entity.
            pub fn get(ecs: &Ecs, e: $crate::Entity) -> Loadout {
                Loadout {
                    $($compname: ecs.$compname.get(e).map(|e| e.clone())),+
                }
            }

            /// Create a new entity in the ECS with this loadout.
            pub fn make(&self, ecs: &mut Ecs) -> $crate::Entity {
                let e = ecs.make();
                $(self.$compname.as_ref().map(|c| ecs.$compname.insert(e, c.clone()));)+
                e
            }

            /// Builder method for adding a component to this loadout.
            pub fn c<C: Component>(mut self, comp: C) -> Loadout {
                comp.add_to_loadout(&mut self);
                self
            }
        }
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<commit_msg>Indenting<commit_after>// !
// Entity component system
//

#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::default::Default;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{hash_map, HashMap, HashSet};
use std::collections::hash_set;

/// Handle for an entity in the entity component system.
///
/// The internal value is the unique identifier for the entity. No two
/// entities should get the same UID during the lifetime of the ECS.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Entity(pub usize);

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(Serialize, Deserialize)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<Entity, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData { data: HashMap::new() }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, e: Entity, comp: C) {
        self.data.insert(e, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, e: Entity) -> bool {
        self.data.contains_key(&e)
    }

    /// Get a reference to a component only if it exists for this entity.
    pub fn get(&self, e: Entity) -> Option<&C> {
        self.data.get(&e)
    }

    /// Get a mutable reference to a component only if it exists for this entity.
    pub fn get_mut(&mut self, e: Entity) -> Option<&mut C> {
        self.data.get_mut(&e)
    }

    /// Iterate entity-component pairs for this component.
    pub fn iter(&self) -> hash_map::Iter<Entity, C> {
        self.data.iter()
    }

    /// Iterate mutable entity-component pairs for this component.
    pub fn iter_mut(&mut self) -> hash_map::IterMut<Entity, C> {
        self.data.iter_mut()
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, e: Entity) -> &'a C {
        self.data.get(&e).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, e: Entity) -> &'a mut C {
        self.data.get_mut(&e).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, e: Entity) {
        self.data.remove(&e);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F) where F: FnMut(&mut AnyComponent);
}

#[derive(Serialize, Deserialize)]
pub struct Ecs<ST> {
    next_uid: usize,
    active: HashSet<Entity>,
    store: ST,
}

impl<ST: Default + Store> Ecs<ST> {
    pub fn new() -> Ecs<ST> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity(next);
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<ST> Deref for Ecs<ST> {
    type Target = ST;

    fn deref(&self) -> &ST {
        &self.store
    }
}

impl<ST> DerefMut for Ecs<ST> {
    fn deref_mut(&mut self) -> &mut ST {
        &mut self.store
    }
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

        #[derive(Serialize, Deserialize)]
        pub struct _ComponentStore {
            $(pub $compname: $crate::ComponentData<$comptype>),+
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: $crate::ComponentData::new()),+
                }
            }
        }

        impl $crate::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut $crate::AnyComponent)
            {
                $(f(&mut self.$compname as &mut $crate::AnyComponent);)+
            }
        }

        #[allow(dead_code)]
        pub fn matches_mask(ecs: &$crate::Ecs<_ComponentStore>, e: $crate::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity);

            /// Add a clone of the component to a loadout struct.
            fn add_to_loadout(self, loadout: &mut Loadout);
        }

        $(impl Component for $comptype {
            fn add_to_ecs(&self, ecs: &mut $crate::Ecs<_ComponentStore>, e: $crate::Entity) {
                ecs.$compname.insert(e, self.clone());
            }

            fn add_to_loadout(self, loadout: &mut Loadout) {
                loadout.$compname = Some(self);
            }
        })+

        pub type Ecs = $crate::Ecs<_ComponentStore>;

        /// A straightforward representation for the complete data of an
        /// entity.
        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Loadout {
            $(pub $compname: Option<$comptype>),+
        }

        impl ::std::default::Default for Loadout {
            fn default() -> Loadout {
                Loadout {
                    $($compname: None),+
                }
            }
        }

        #[allow(dead_code)]
        impl Loadout {
            /// Create a new blank loadout.
            pub fn new() -> Loadout { Default::default() }

            /// Get the loadout that corresponds to an existing entity.
            pub fn get(ecs: &Ecs, e: $crate::Entity) -> Loadout {
                Loadout {
                    $($compname: ecs.$compname.get(e).map(|e| e.clone())),+
                }
            }

            /// Create a new entity in the ECS with this loadout.
            pub fn make(&self, ecs: &mut Ecs) -> $crate::Entity {
                let e = ecs.make();
                $(self.$compname.as_ref().map(|c| ecs.$compname.insert(e, c.clone()));)+
                e
            }

            /// Builder method for adding a component to this loadout.
            pub fn c<C: Component>(mut self, comp: C) -> Loadout {
                comp.add_to_loadout(&mut self);
                self
            }
        }
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<|endoftext|>


<commit_before>use std::fmt;

// TODO: figure out how to use failure for error (or some other pattern)
#[derive(Debug)]
pub enum Error {
    NotAnInstruction,
    LongInstruction,
}

/// FlowMeta is metadata that describes code flow for an instruction.
///
/// The metadata is packed into a single byte, with the expectation that,
///  there may be one `FlowMeta` instance for each (code) offset in a program.
/// However, the you should not be worried about the representation, just the interface.
#[derive(Debug, Clone, Copy)]
pub struct FlowMeta(u8);

impl FlowMeta {
    // layout:
    //
    //     +-+-+-+-+-+-+-+-+
    //     |A|B|C|D|   E   |
    //     +-+-+-+-+-+-+-+-+
    //
    //  A - has xrefs to
    //  B - has xrefs from
    //  C - does other fallthrough to
    //  D - does fallthrough
    //  E - insn size

    pub fn zero() -> FlowMeta {
        FlowMeta(0x0)
    }

    /// Fetch the cached length of the instruction.
    ///
    /// If longer than 14 bytes, then will return `Error::LongInstruction` and you'll have to decode
    ///  the instruction yourself.
    ///
    /// Errors:
    ///   - NotAnInstruction
    ///   - LongInstruction
    pub fn get_insn_length(self) -> Result<u8, Error> {
        let v = self.0 & 0b0000_1111;
        match v {
            0x00 => Err(Error::NotAnInstruction),
            0x0F => Err(Error::LongInstruction),
            v => Ok(v),
        }
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    ///
    /// m.set_insn_length(0);
    /// assert_eq!(m.is_insn(), false);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::NotAnInstruction));
    ///
    /// m.set_insn_length(1);
    /// assert_eq!(m.is_insn(), true);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x1);
    ///
    /// m.set_insn_length(2);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x2);
    ///
    /// m.set_insn_length(0xE);
    /// assert_eq!(m.get_insn_length().unwrap(), 0xE);
    ///
    /// m.set_insn_length(0xF);
    /// assert_eq!(m.is_insn(), true);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::LongInstruction));
    /// ```
    pub fn set_insn_length(&mut self, length: u8) {
        let len = if length >= 0xF {
            // instrunction length too long
            0x0F
        } else if length == 0x0 {
            // not an instruction
            0x00
        } else {
            // good flow
            length & 0x0F
        };

        self.0 = (self.0 & 0b1111_0000) | len;
    }

    pub fn is_insn(self) -> bool {
        self.0 & 0b0000_1111 != 0
    }

    /// Does the instruction fallthrough?
    pub fn does_fallthrough(self) -> bool {
        self.0 & 0b0001_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.does_fallthrough(), false);
    ///
    /// m.set_fallthrough();
    /// assert_eq!(m.does_fallthrough(), true);
    /// ```
    pub fn set_fallthrough(&mut self) {
        self.0 |= 0b0001_0000;
    }

    /// Does another instruction fallthrough to this instruction?
    pub fn does_other_fallthrough_to(self) -> bool {
        self.0 & 0b0010_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.does_other_fallthrough_to(), false);
    ///
    /// m.set_other_fallthrough_to();
    /// assert_eq!(m.does_other_fallthrough_to(), true);
    /// ```
    pub fn set_other_fallthrough_to(&mut self) {
        self.0 |= 0b0010_0000;
    }

    /// Does the instruction have flow xrefs from it?
    /// This does not include the fallthrough flow.
    pub fn has_xrefs_from(self) -> bool {
        self.0 & 0b0100_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_from(), false);
    ///
    /// m.set_xrefs_from();
    /// assert_eq!(m.has_xrefs_from(), true);
    /// ```
    pub fn set_xrefs_from(&mut self) {
        self.0 |= 0b0100_0000;
    }

    /// Does the instruction have flow xrefs to it?
    pub fn has_xrefs_to(self) -> bool {
        self.0 & 0b1000_0000 > 0
    }

    /// Set the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    /// ```
    pub fn set_xrefs_to(&mut self) {
        self.0 |= 0b1000_0000;
    }

    /// Unset the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    ///
    /// m.unset_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), false);
    /// ```
    pub fn unset_xrefs_to(&mut self) {
        self.0 &= 0b0111_1111
    }
}

impl fmt::Display for FlowMeta {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "FlowMeta{{length: {}, fallthrough: {}, xrefs to: {}, xrefs from: {}}}",
            match self.get_insn_length() {
                Ok(v) => format!("0x{:x}", v),
                Err(Error::LongInstruction) => ">=0xF".to_string(),
                Err(Error::NotAnInstruction) => "not an instruction".to_string(),
            },
            self.does_fallthrough(),
            self.has_xrefs_to(),
            self.has_xrefs_from()
        )
    }
}
<commit_msg>flowmeta: derive errors from failure<commit_after>use std::fmt;

use failure::{Fail};

#[derive(Debug, Fail)]
pub enum Error {
    #[fail(display = "Not an instruction")]
    NotAnInstruction,
    #[fail(display = "Instruction too long")]
    LongInstruction,
}

/// FlowMeta is metadata that describes code flow for an instruction.
///
/// The metadata is packed into a single byte, with the expectation that,
///  there may be one `FlowMeta` instance for each (code) offset in a program.
/// However, the you should not be worried about the representation, just the interface.
#[derive(Debug, Clone, Copy)]
pub struct FlowMeta(u8);

impl FlowMeta {
    // layout:
    //
    //     +-+-+-+-+-+-+-+-+
    //     |A|B|C|D|   E   |
    //     +-+-+-+-+-+-+-+-+
    //
    //  A - has xrefs to
    //  B - has xrefs from
    //  C - does other fallthrough to
    //  D - does fallthrough
    //  E - insn size

    pub fn zero() -> FlowMeta {
        FlowMeta(0x0)
    }

    /// Fetch the cached length of the instruction.
    ///
    /// If longer than 14 bytes, then will return `Error::LongInstruction` and you'll have to decode
    ///  the instruction yourself.
    ///
    /// Errors:
    ///   - NotAnInstruction
    ///   - LongInstruction
    pub fn get_insn_length(self) -> Result<u8, Error> {
        let v = self.0 & 0b0000_1111;
        match v {
            0x00 => Err(Error::NotAnInstruction),
            0x0F => Err(Error::LongInstruction),
            v => Ok(v),
        }
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    ///
    /// m.set_insn_length(0);
    /// assert_eq!(m.is_insn(), false);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::NotAnInstruction));
    ///
    /// m.set_insn_length(1);
    /// assert_eq!(m.is_insn(), true);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x1);
    ///
    /// m.set_insn_length(2);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x2);
    ///
    /// m.set_insn_length(0xE);
    /// assert_eq!(m.get_insn_length().unwrap(), 0xE);
    ///
    /// m.set_insn_length(0xF);
    /// assert_eq!(m.is_insn(), true);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::LongInstruction));
    /// ```
    pub fn set_insn_length(&mut self, length: u8) {
        let len = if length >= 0xF {
            // instrunction length too long
            0x0F
        } else if length == 0x0 {
            // not an instruction
            0x00
        } else {
            // good flow
            length & 0x0F
        };

        self.0 = (self.0 & 0b1111_0000) | len;
    }

    pub fn is_insn(self) -> bool {
        self.0 & 0b0000_1111 != 0
    }

    /// Does the instruction fallthrough?
    pub fn does_fallthrough(self) -> bool {
        self.0 & 0b0001_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.does_fallthrough(), false);
    ///
    /// m.set_fallthrough();
    /// assert_eq!(m.does_fallthrough(), true);
    /// ```
    pub fn set_fallthrough(&mut self) {
        self.0 |= 0b0001_0000;
    }

    /// Does another instruction fallthrough to this instruction?
    pub fn does_other_fallthrough_to(self) -> bool {
        self.0 & 0b0010_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.does_other_fallthrough_to(), false);
    ///
    /// m.set_other_fallthrough_to();
    /// assert_eq!(m.does_other_fallthrough_to(), true);
    /// ```
    pub fn set_other_fallthrough_to(&mut self) {
        self.0 |= 0b0010_0000;
    }

    /// Does the instruction have flow xrefs from it?
    /// This does not include the fallthrough flow.
    pub fn has_xrefs_from(self) -> bool {
        self.0 & 0b0100_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_from(), false);
    ///
    /// m.set_xrefs_from();
    /// assert_eq!(m.has_xrefs_from(), true);
    /// ```
    pub fn set_xrefs_from(&mut self) {
        self.0 |= 0b0100_0000;
    }

    /// Does the instruction have flow xrefs to it?
    pub fn has_xrefs_to(self) -> bool {
        self.0 & 0b1000_0000 > 0
    }

    /// Set the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    /// ```
    pub fn set_xrefs_to(&mut self) {
        self.0 |= 0b1000_0000;
    }

    /// Unset the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    ///
    /// m.unset_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), false);
    /// ```
    pub fn unset_xrefs_to(&mut self) {
        self.0 &= 0b0111_1111
    }
}

impl fmt::Display for FlowMeta {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "FlowMeta{{length: {}, fallthrough: {}, xrefs to: {}, xrefs from: {}}}",
            match self.get_insn_length() {
                Ok(v) => format!("0x{:x}", v),
                Err(Error::LongInstruction) => ">=0xF".to_string(),
                Err(Error::NotAnInstruction) => "not an instruction".to_string(),
            },
            self.does_fallthrough(),
            self.has_xrefs_to(),
            self.has_xrefs_from()
        )
    }
}
<|endoftext|>


<commit_before>use std::iter::once;

use hir::Semantics;
use ide_db::{base_db::FileRange, RootDatabase};
use itertools::Itertools;
use syntax::{
    algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use text_edit::{TextEdit, TextEditBuilder};

pub enum Direction {
    Up,
    Down,
}

// Feature: Move Item
//
// Move item under cursor or selection up and down.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Move item up**
// | VS Code | **Rust Analyzer: Move item down**
// |===
pub(crate) fn move_item(
    db: &RootDatabase,
    range: FileRange,
    direction: Direction,
) -> Option<TextEdit> {
    let sema = Semantics::new(db);
    let file = sema.parse(range.file_id);

    let item = file.syntax().covering_element(range.range);
    find_ancestors(item, direction, range.range)
}

fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
    let root = match item {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent()?,
    };

    let movable = [
        SyntaxKind::ARG_LIST,
        SyntaxKind::MATCH_ARM,
        SyntaxKind::PARAM,
        SyntaxKind::LET_STMT,
        SyntaxKind::EXPR_STMT,
        SyntaxKind::MATCH_EXPR,
        SyntaxKind::MACRO_CALL,
        SyntaxKind::TYPE_ALIAS,
        SyntaxKind::TRAIT,
        SyntaxKind::IMPL,
        SyntaxKind::MACRO_DEF,
        SyntaxKind::STRUCT,
        SyntaxKind::UNION,
        SyntaxKind::ENUM,
        SyntaxKind::FN,
        SyntaxKind::MODULE,
        SyntaxKind::USE,
        SyntaxKind::STATIC,
        SyntaxKind::CONST,
        SyntaxKind::MACRO_RULES,
    ];

    let ancestor = once(root.clone())
        .chain(root.ancestors())
        .find(|ancestor| movable.contains(&ancestor.kind()))?;

    move_in_direction(&ancestor, direction, range)
}

fn move_in_direction(
    node: &SyntaxNode,
    direction: Direction,
    range: TextRange,
) -> Option<TextEdit> {
    match_ast! {
        match node {
            ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction),
            _ => Some(replace_nodes(node, &match direction {
                Direction::Up => node.prev_sibling(),
                Direction::Down => node.next_sibling(),
            }?))
        }
    }
}

fn swap_sibling_in_list<'i, A: AstNode + Clone, I: Iterator<Item = A>>(
    list: I,
    range: TextRange,
    direction: Direction,
) -> Option<TextEdit> {
    let (l, r) = list
        .tuple_windows()
        .filter(|(l, r)| match direction {
            Direction::Up => r.syntax().text_range().contains_range(range),
            Direction::Down => l.syntax().text_range().contains_range(range),
        })
        .next()?;

    Some(replace_nodes(l.syntax(), r.syntax()))
}

fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
    let mut edit = TextEditBuilder::default();

    algo::diff(first, second).into_text_edit(&mut edit);
    algo::diff(second, first).into_text_edit(&mut edit);

    edit.finish()
}

#[cfg(test)]
mod tests {
    use crate::fixture;
    use expect_test::{expect, Expect};

    use crate::Direction;

    fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
        let (analysis, range) = fixture::range(ra_fixture);
        let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
        let mut file = analysis.file_text(range.file_id).unwrap().to_string();
        edit.apply(&mut file);
        expect.assert_eq(&file);
    }

    #[test]
    fn test_moves_match_arm_up() {
        check(
            r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false =>$0$0 {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_arm_down() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_let_stmt_up() {
        check(
            r#"
fn main() {
    let test = 123;
    let test2$0$0 = 456;
}
            "#,
            expect![[r#"
fn main() {
    let test2 = 456;
    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_expr_up() {
        check(
            r#"
fn main() {
    println!("Hello, world");
    println!("All I want to say is...");$0$0
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_nowhere_to_move_stmt() {
        check(
            r#"
fn main() {
    println!("All I want to say is...");$0$0
    println!("Hello, world");
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_item() {
        check(
            r#"
fn main() {}

fn foo() {}$0$0
            "#,
            expect![[r#"
fn foo() {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_impl_up() {
        check(
            r#"
struct Yay;

trait Wow {}

impl Wow for Yay {}$0$0
            "#,
            expect![[r#"
struct Yay;

impl Wow for Yay {}

trait Wow {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_use_up() {
        check(
            r#"
use std::vec::Vec;
use std::collections::HashMap$0$0;
            "#,
            expect![[r#"
use std::collections::HashMap;
use std::vec::Vec;
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_expr_up() {
        check(
            r#"
fn main() {
    let test = 123;

    $0match test {
        456 => {},
        _ => {}
    };$0
}
            "#,
            expect![[r#"
fn main() {
    match test {
        456 => {},
        _ => {}
    };

    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_param_up() {
        check(
            r#"
fn test(one: i32, two$0$0: u32) {}

fn main() {
    test(123, 456);
}
            "#,
            expect![[r#"
fn test(two: u32, one: i32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_up() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456$0$0);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_down() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move_arg() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_prioritizes_trait_items() {
        check(
            r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    type Two = u32;

    fn inner() {$0$0
        println!("Mmmm");
    }
}
            "#,
            expect![[r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    fn inner() {
        println!("Mmmm");
    }

    type Two = u32;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_weird_nesting() {
        check(
            r#"
fn test() {
    mod hello {
        fn inner() {}
    }

    mod hi {$0$0
        fn inner() {}
    }
}
            "#,
            expect![[r#"
fn test() {
    mod hi {
        fn inner() {}
    }

    mod hello {
        fn inner() {}
    }
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn handles_empty_file() {
        check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
    }
}
<commit_msg>Added more movable lists<commit_after>use std::iter::once;

use hir::Semantics;
use ide_db::{base_db::FileRange, RootDatabase};
use itertools::Itertools;
use syntax::{
    algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use text_edit::{TextEdit, TextEditBuilder};

pub enum Direction {
    Up,
    Down,
}

// Feature: Move Item
//
// Move item under cursor or selection up and down.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Move item up**
// | VS Code | **Rust Analyzer: Move item down**
// |===
pub(crate) fn move_item(
    db: &RootDatabase,
    range: FileRange,
    direction: Direction,
) -> Option<TextEdit> {
    let sema = Semantics::new(db);
    let file = sema.parse(range.file_id);

    let item = file.syntax().covering_element(range.range);
    find_ancestors(item, direction, range.range)
}

fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
    let root = match item {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent()?,
    };

    let movable = [
        SyntaxKind::ARG_LIST,
        SyntaxKind::GENERIC_PARAM_LIST,
        SyntaxKind::GENERIC_ARG_LIST,
        SyntaxKind::VARIANT_LIST,
        SyntaxKind::TYPE_BOUND_LIST,
        SyntaxKind::MATCH_ARM,
        SyntaxKind::PARAM,
        SyntaxKind::LET_STMT,
        SyntaxKind::EXPR_STMT,
        SyntaxKind::MATCH_EXPR,
        SyntaxKind::MACRO_CALL,
        SyntaxKind::TYPE_ALIAS,
        SyntaxKind::TRAIT,
        SyntaxKind::IMPL,
        SyntaxKind::MACRO_DEF,
        SyntaxKind::STRUCT,
        SyntaxKind::UNION,
        SyntaxKind::ENUM,
        SyntaxKind::FN,
        SyntaxKind::MODULE,
        SyntaxKind::USE,
        SyntaxKind::STATIC,
        SyntaxKind::CONST,
        SyntaxKind::MACRO_RULES,
    ];

    let ancestor = once(root.clone())
        .chain(root.ancestors())
        .find(|ancestor| movable.contains(&ancestor.kind()))?;

    move_in_direction(&ancestor, direction, range)
}

fn move_in_direction(
    node: &SyntaxNode,
    direction: Direction,
    range: TextRange,
) -> Option<TextEdit> {
    match_ast! {
        match node {
            ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction),
            ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction),
            ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction),
            ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction),
            ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction),
            _ => Some(replace_nodes(node, &match direction {
                Direction::Up => node.prev_sibling(),
                Direction::Down => node.next_sibling(),
            }?))
        }
    }
}

fn swap_sibling_in_list<'i, A: AstNode + Clone, I: Iterator<Item = A>>(
    list: I,
    range: TextRange,
    direction: Direction,
) -> Option<TextEdit> {
    let (l, r) = list
        .tuple_windows()
        .filter(|(l, r)| match direction {
            Direction::Up => r.syntax().text_range().contains_range(range),
            Direction::Down => l.syntax().text_range().contains_range(range),
        })
        .next()?;

    Some(replace_nodes(l.syntax(), r.syntax()))
}

fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
    let mut edit = TextEditBuilder::default();

    algo::diff(first, second).into_text_edit(&mut edit);
    algo::diff(second, first).into_text_edit(&mut edit);

    edit.finish()
}

#[cfg(test)]
mod tests {
    use crate::fixture;
    use expect_test::{expect, Expect};

    use crate::Direction;

    fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
        let (analysis, range) = fixture::range(ra_fixture);
        let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
        let mut file = analysis.file_text(range.file_id).unwrap().to_string();
        edit.apply(&mut file);
        expect.assert_eq(&file);
    }

    #[test]
    fn test_moves_match_arm_up() {
        check(
            r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false =>$0$0 {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_arm_down() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        false => {
            println!("Test");
        },
        true => {
            println!("Hello, world");
        }
    };
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move() {
        check(
            r#"
fn main() {
    match true {
        true =>$0$0 {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#,
            expect![[r#"
fn main() {
    match true {
        true => {
            println!("Hello, world");
        },
        false => {
            println!("Test");
        }
    };
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_let_stmt_up() {
        check(
            r#"
fn main() {
    let test = 123;
    let test2$0$0 = 456;
}
            "#,
            expect![[r#"
fn main() {
    let test2 = 456;
    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_expr_up() {
        check(
            r#"
fn main() {
    println!("Hello, world");
    println!("All I want to say is...");$0$0
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_nowhere_to_move_stmt() {
        check(
            r#"
fn main() {
    println!("All I want to say is...");$0$0
    println!("Hello, world");
}
            "#,
            expect![[r#"
fn main() {
    println!("All I want to say is...");
    println!("Hello, world");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_item() {
        check(
            r#"
fn main() {}

fn foo() {}$0$0
            "#,
            expect![[r#"
fn foo() {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_impl_up() {
        check(
            r#"
struct Yay;

trait Wow {}

impl Wow for Yay $0$0{}
            "#,
            expect![[r#"
struct Yay;

impl Wow for Yay {}

trait Wow {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_move_use_up() {
        check(
            r#"
use std::vec::Vec;
use std::collections::HashMap$0$0;
            "#,
            expect![[r#"
use std::collections::HashMap;
use std::vec::Vec;
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_match_expr_up() {
        check(
            r#"
fn main() {
    let test = 123;

    $0match test {
        456 => {},
        _ => {}
    };$0
}
            "#,
            expect![[r#"
fn main() {
    match test {
        456 => {},
        _ => {}
    };

    let test = 123;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_param_up() {
        check(
            r#"
fn test(one: i32, two$0$0: u32) {}

fn main() {
    test(123, 456);
}
            "#,
            expect![[r#"
fn test(two: u32, one: i32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_up() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456$0$0);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_arg_down() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(456, 123);
}
            "#]],
            Direction::Down,
        );
    }

    #[test]
    fn test_nowhere_to_move_arg() {
        check(
            r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123$0$0, 456);
}
            "#,
            expect![[r#"
fn test(one: i32, two: u32) {}

fn main() {
    test(123, 456);
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_param_up() {
        check(
            r#"
struct Test<A, B$0$0>(A, B);

fn main() {}
            "#,
            expect![[r#"
struct Test<B, A>(A, B);

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_generic_arg_up() {
        check(
            r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<i32, &str$0$0>(123, "yay");
}
            "#,
            expect![[r#"
struct Test<A, B>(A, B);

fn main() {
    let t = Test::<&str, i32>(123, "yay");
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_variant_up() {
        check(
            r#"
enum Hello {
    One,
    Two$0$0
}

fn main() {}
            "#,
            expect![[r#"
enum Hello {
    Two,
    One
}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_moves_type_bound_up() {
        check(
            r#"
trait One {}

trait Two {}

fn test<T: One + Two$0$0>(t: T) {}

fn main() {}
            "#,
            expect![[r#"
trait One {}

trait Two {}

fn test<T: Two + One>(t: T) {}

fn main() {}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_prioritizes_trait_items() {
        check(
            r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    type Two = u32;

    fn inner() {$0$0
        println!("Mmmm");
    }
}
            "#,
            expect![[r#"
struct Test;

trait Yay {
    type One;

    type Two;

    fn inner();
}

impl Yay for Test {
    type One = i32;

    fn inner() {
        println!("Mmmm");
    }

    type Two = u32;
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn test_weird_nesting() {
        check(
            r#"
fn test() {
    mod hello {
        fn inner() {}
    }

    mod hi {$0$0
        fn inner() {}
    }
}
            "#,
            expect![[r#"
fn test() {
    mod hi {
        fn inner() {}
    }

    mod hello {
        fn inner() {}
    }
}
            "#]],
            Direction::Up,
        );
    }

    #[test]
    fn handles_empty_file() {
        check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
    }
}
<|endoftext|>


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

use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::LitKind;
use crate::utils::{is_expn_of, match_def_path, opt_def_id, resolve_node, span_lint, span_lint_and_sugg};
use if_chain::if_chain;

/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
/// replaced with `(e)print!()` / `(e)println!()`
///
/// **Why is this bad?** Using `(e)println! is clearer and more concise
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // this would be clearer as `eprintln!("foo: {:?}", bar);`
/// writeln!(&mut io::stderr(), "foo: {:?}", bar).unwrap();
/// ```
declare_clippy_lint! {
    pub EXPLICIT_WRITE,
    complexity,
    "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXPLICIT_WRITE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {
            // match call to unwrap
            if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.node;
            if unwrap_fun.ident.name == "unwrap";
            // match call to write_fmt
            if unwrap_args.len() > 0;
            if let ExprKind::MethodCall(ref write_fun, _, ref write_args) =
                unwrap_args[0].node;
            // Obtain the string that should be printed
            if write_args.len() > 1;
            if let ExprKind::Call(_, ref output_args) = write_args[1].node;
            if output_args.len() > 0;
            if let ExprKind::AddrOf(_, ref output_string_expr) = output_args[0].node;
            if let ExprKind::Array(ref string_exprs) = output_string_expr.node;
            if string_exprs.len() > 0;
            if let ExprKind::Lit(ref lit) = string_exprs[0].node;
            if let LitKind::Str(ref write_output, _) = lit.node;
            if write_fun.ident.name == "write_fmt";
            // match calls to std::io::stdout() / std::io::stderr ()
            if write_args.len() > 0;
            if let ExprKind::Call(ref dest_fun, _) = write_args[0].node;
            if let ExprKind::Path(ref qpath) = dest_fun.node;
            if let Some(dest_fun_id) =
                opt_def_id(resolve_node(cx, qpath, dest_fun.hir_id));
            if let Some(dest_name) = if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stdout"]) {
                Some("stdout")
            } else if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stderr"]) {
                Some("stderr")
            } else {
                None
            };
            then {
                let write_span = unwrap_args[0].span;
                let calling_macro =
                    // ordering is important here, since `writeln!` uses `write!` internally
                    if is_expn_of(write_span, "writeln").is_some() {
                        Some("writeln")
                    } else if is_expn_of(write_span, "write").is_some() {
                        Some("write")
                    } else {
                        None
                    };
                let prefix = if dest_name == "stderr" {
                    "e"
                } else {
                    ""
                };

                // We need to remove the last trailing newline from the string because the
                // underlying `fmt::write` function doesn't know wether `println!` or `print!` was
                // used.
                let mut write_output: String = write_output.to_string();
                if write_output.ends_with('\n') {
                    write_output.truncate(write_output.len() - 1)
                }
                if let Some(macro_name) = calling_macro {
                    span_lint_and_sugg(
                        cx,
                        EXPLICIT_WRITE,
                        expr.span,
                        &format!(
                            "use of `{}!({}(), ...).unwrap()`",
                            macro_name,
                            dest_name
                        ),
                        "try this",
                        format!("{}{}!(\"{}\")", prefix, macro_name.replace("write", "print"), write_output.escape_default())
                    );
                } else {
                    span_lint_and_sugg(
                        cx,
                        EXPLICIT_WRITE,
                        expr.span,
                        &format!("use of `{}().write_fmt(...).unwrap()`", dest_name),
                        "try this",
                        format!("{}print!(\"{}\")", prefix, write_output.escape_default())
                    );
                }
            }
        }
    }
}
<commit_msg>Extract method<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::LitKind;
use crate::utils::{is_expn_of, match_def_path, opt_def_id, resolve_node, span_lint, span_lint_and_sugg};
use if_chain::if_chain;

/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
/// replaced with `(e)print!()` / `(e)println!()`
///
/// **Why is this bad?** Using `(e)println! is clearer and more concise
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // this would be clearer as `eprintln!("foo: {:?}", bar);`
/// writeln!(&mut io::stderr(), "foo: {:?}", bar).unwrap();
/// ```
declare_clippy_lint! {
    pub EXPLICIT_WRITE,
    complexity,
    "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXPLICIT_WRITE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {
            // match call to unwrap
            if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.node;
            if unwrap_fun.ident.name == "unwrap";
            // match call to write_fmt
            if unwrap_args.len() > 0;
            if let ExprKind::MethodCall(ref write_fun, _, ref write_args) =
                unwrap_args[0].node;
            if write_fun.ident.name == "write_fmt";
            // match calls to std::io::stdout() / std::io::stderr ()
            if write_args.len() > 0;
            if let ExprKind::Call(ref dest_fun, _) = write_args[0].node;
            if let ExprKind::Path(ref qpath) = dest_fun.node;
            if let Some(dest_fun_id) =
                opt_def_id(resolve_node(cx, qpath, dest_fun.hir_id));
            if let Some(dest_name) = if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stdout"]) {
                Some("stdout")
            } else if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stderr"]) {
                Some("stderr")
            } else {
                None
            };
            then {
                let write_span = unwrap_args[0].span;
                let calling_macro =
                    // ordering is important here, since `writeln!` uses `write!` internally
                    if is_expn_of(write_span, "writeln").is_some() {
                        Some("writeln")
                    } else if is_expn_of(write_span, "write").is_some() {
                        Some("write")
                    } else {
                        None
                    };
                let prefix = if dest_name == "stderr" {
                    "e"
                } else {
                    ""
                };

                // We need to remove the last trailing newline from the string because the
                // underlying `fmt::write` function doesn't know wether `println!` or `print!` was
                // used.
                let mut write_output: String = write_output_string(write_args).unwrap();
                if write_output.ends_with('\n') {
                    write_output.truncate(write_output.len() - 1)
                }
                if let Some(macro_name) = calling_macro {
                    span_lint_and_sugg(
                        cx,
                        EXPLICIT_WRITE,
                        expr.span,
                        &format!(
                            "use of `{}!({}(), ...).unwrap()`",
                            macro_name,
                            dest_name
                        ),
                        "try this",
                        format!("{}{}!(\"{}\")", prefix, macro_name.replace("write", "print"), write_output.escape_default())
                    );
                } else {
                    span_lint_and_sugg(
                        cx,
                        EXPLICIT_WRITE,
                        expr.span,
                        &format!("use of `{}().write_fmt(...).unwrap()`", dest_name),
                        "try this",
                        format!("{}print!(\"{}\")", prefix, write_output.escape_default())
                    );
                }
            }
        }
    }
}

// Extract the output string from the given `write_args`.
fn write_output_string(write_args: &HirVec<Expr>) -> Option<String> {
    if_chain! {
        // Obtain the string that should be printed
        if write_args.len() > 1;
        if let ExprKind::Call(_, ref output_args) = write_args[1].node;
        if output_args.len() > 0;
        if let ExprKind::AddrOf(_, ref output_string_expr) = output_args[0].node;
        if let ExprKind::Array(ref string_exprs) = output_string_expr.node;
        if string_exprs.len() > 0;
        if let ExprKind::Lit(ref lit) = string_exprs[0].node;
        if let LitKind::Str(ref write_output, _) = lit.node;
        then {
            return Some(write_output.to_string())
        }
    }
    None
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
struct CubeSat {
    id: u64,
}

#[derive(Debug)]
enum StatusMessage {
    Ok,
}

fn check_status(_sat_id: CubeSat) -> StatusMessage {
    StatusMessage::Ok
}

fn main() {
    let sat_a = CubeSat { id: 0 };
    let sat_b = CubeSat { id: 1 };
    let sat_c = CubeSat { id: 2 };

    let a_status = check_status(sat_a);
    let b_status = check_status(sat_b);
    let c_status = check_status(sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);

    // "waiting" ...
    let a_status = check_status(sat_a);
    let b_status = check_status(sat_b);
    let c_status = check_status(sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);
}
<commit_msg>fix by using references<commit_after>
#[derive(Debug)]
struct CubeSat {
    id: u64,
}

#[derive(Debug)]
enum StatusMessage {
    Ok,
}

fn check_status(_sat_id: &CubeSat) -> StatusMessage {
    StatusMessage::Ok
}

fn main() {
    let sat_a = CubeSat { id: 0 };
    let sat_b = CubeSat { id: 1 };
    let sat_c = CubeSat { id: 2 };

    let a_status = check_status(&sat_a);
    let b_status = check_status(&sat_b);
    let c_status = check_status(&sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);

    // "waiting" ...
    let a_status = check_status(&sat_a);
    let b_status = check_status(&sat_b);
    let c_status = check_status(&sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);
}
<|endoftext|>