<commit_before>// Copyright 2017 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.

use dataflow::{FlowAtLocation, FlowsAtLocation};
use borrow_check::nll::region_infer::Cause;
use dataflow::MaybeInitializedPlaces;
use dataflow::move_paths::{HasMoveData, MoveData};
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use rustc::infer::InferOk;
use borrow_check::nll::type_check::AtLocation;
use util::liveness::LivenessResults;

use super::TypeChecker;

/// Combines liveness analysis with initialization analysis to
/// determine which variables are live at which points, both due to
/// ordinary uses and drops. Returns a set of (ty, location) pairs
/// that indicate which types must be live at which point in the CFG.
/// This vector is consumed by `constraint_generation`.
///
/// NB. This computation requires normalization; therefore, it must be
/// performed before
pub(super) fn generate<'gcx, 'tcx>(
    cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
    mir: &Mir<'tcx>,
    liveness: &LivenessResults,
    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
    move_data: &MoveData<'tcx>,
) {
    let tcx = cx.tcx();
    let mut generator = TypeLivenessGenerator {
        cx,
        tcx,
        mir,
        liveness,
        flow_inits,
        move_data,
    };

    for bb in mir.basic_blocks().indices() {
        generator.add_liveness_constraints(bb);
    }
}

struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
where
    'typeck: 'gen,
    'flow: 'gen,
    'tcx: 'typeck + 'flow,
    'gcx: 'tcx,
{
    cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
    tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
    mir: &'gen Mir<'tcx>,
    liveness: &'gen LivenessResults,
    flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
    move_data: &'gen MoveData<'tcx>,
}

impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
    /// Liveness constraints:
    ///
    /// > If a variable V is live at point P, then all regions R in the type of V
    /// > must include the point P.
    fn add_liveness_constraints(&mut self, bb: BasicBlock) {
        debug!("add_liveness_constraints(bb={:?})", bb);

        self.liveness
            .regular
            .simulate_block(self.mir, bb, |location, live_locals| {
                for live_local in live_locals.iter() {
                    let live_local_ty = self.mir.local_decls[live_local].ty;
                    let cause = Cause::LiveVar(live_local, location);
                    self.push_type_live_constraint(live_local_ty, location, cause);
                }
            });

        let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
        self.liveness
            .drop
            .simulate_block(self.mir, bb, |location, live_locals| {
                all_live_locals.push((location, live_locals.iter().collect()));
            });
        debug!(
            "add_liveness_constraints: all_live_locals={:#?}",
            all_live_locals
        );

        let terminator_index = self.mir.basic_blocks()[bb].statements.len();
        self.flow_inits.reset_to_entry_of(bb);
        while let Some((location, live_locals)) = all_live_locals.pop() {
            for live_local in live_locals {
                debug!(
                    "add_liveness_constraints: location={:?} live_local={:?}",
                    location, live_local
                );

                self.flow_inits.each_state_bit(|mpi_init| {
                    debug!(
                        "add_liveness_constraints: location={:?} initialized={:?}",
                        location,
                        &self.flow_inits.operator().move_data().move_paths[mpi_init]
                    );
                });

                let mpi = self.move_data.rev_lookup.find_local(live_local);
                if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
                    debug!(
                        "add_liveness_constraints: mpi={:?} has initialized child {:?}",
                        self.move_data.move_paths[mpi],
                        self.move_data.move_paths[initialized_child]
                    );

                    let live_local_ty = self.mir.local_decls[live_local].ty;
                    self.add_drop_live_constraint(live_local, live_local_ty, location);
                }
            }

            if location.statement_index == terminator_index {
                debug!(
                    "add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
                    location
                );
                self.flow_inits.reconstruct_terminator_effect(location);
            } else {
                debug!(
                    "add_liveness_constraints: reconstruct_statement_effect from {:#?}",
                    location
                );
                self.flow_inits.reconstruct_statement_effect(location);
            }
            self.flow_inits.apply_local_effect(location);
        }
    }

    /// Some variable with type `live_ty` is "regular live" at
    /// `location` -- i.e., it may be used later. This means that all
    /// regions appearing in the type `live_ty` must be live at
    /// `location`.
    fn push_type_live_constraint<T>(&mut self, value: T, location: Location, cause: Cause)
    where
        T: TypeFoldable<'tcx>,
    {
        debug!(
            "push_type_live_constraint(live_ty={:?}, location={:?})",
            value, location
        );

        self.tcx.for_each_free_region(&value, |live_region| {
            self.cx
                .constraints
                .liveness_set
                .push((live_region, location, cause.clone()));
        });
    }

    /// Some variable with type `live_ty` is "drop live" at `location`
    /// -- i.e., it may be dropped later. This means that *some* of
    /// the regions in its type must be live at `location`. The
    /// precise set will depend on the dropck constraints, and in
    /// particular this takes `#[may_dangle]` into account.
    fn add_drop_live_constraint(
        &mut self,
        dropped_local: Local,
        dropped_ty: Ty<'tcx>,
        location: Location,
    ) {
        debug!(
            "add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})",
            dropped_local, dropped_ty, location
        );

        // If we end visiting the same type twice (usually due to a cycle involving
        // associated types), we need to ensure that its region types match up with the type
        // we added to the 'known' map the first time around. For this reason, we need
        // our infcx to hold onto its calculated region constraints after each call
        // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
        // type will end up instantiating the type with a new set of inference variables
        // Since this new type will never be in 'known', we end up looping forever.
        //
        // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
        // ourselves in one large 'fully_perform_op' callback.
        let kind_constraints = self.cx
            .fully_perform_op(location.at_self(), |cx| {
                let span = cx.last_span;

                let mut final_obligations = Vec::new();
                let mut kind_constraints = Vec::new();

                let InferOk {
                    value: kinds,
                    obligations,
                } = cx.infcx
                    .at(&cx.misc(span), cx.param_env)
                    .dropck_outlives(dropped_ty);
                for kind in kinds {
                    // All things in the `outlives` array may be touched by
                    // the destructor and must be live at this point.
                    let cause = Cause::DropVar(dropped_local, location);
                    kind_constraints.push((kind, location, cause));
                }

                final_obligations.extend(obligations);

                Ok(InferOk {
                    value: kind_constraints,
                    obligations: final_obligations,
                })
            })
            .unwrap();

        for (kind, location, cause) in kind_constraints {
            self.push_type_live_constraint(kind, location, cause);
        }
    }
}
<commit_msg>Rollup merge of #51399 - ngg:nll-performance, r=nikomatsakis<commit_after>// Copyright 2017 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.

use dataflow::{FlowAtLocation, FlowsAtLocation};
use borrow_check::nll::region_infer::Cause;
use dataflow::MaybeInitializedPlaces;
use dataflow::move_paths::{HasMoveData, MoveData};
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use rustc::infer::InferOk;
use borrow_check::nll::type_check::AtLocation;
use util::liveness::LivenessResults;

use super::TypeChecker;

/// Combines liveness analysis with initialization analysis to
/// determine which variables are live at which points, both due to
/// ordinary uses and drops. Returns a set of (ty, location) pairs
/// that indicate which types must be live at which point in the CFG.
/// This vector is consumed by `constraint_generation`.
///
/// NB. This computation requires normalization; therefore, it must be
/// performed before
pub(super) fn generate<'gcx, 'tcx>(
    cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
    mir: &Mir<'tcx>,
    liveness: &LivenessResults,
    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
    move_data: &MoveData<'tcx>,
) {
    let tcx = cx.tcx();
    let mut generator = TypeLivenessGenerator {
        cx,
        tcx,
        mir,
        liveness,
        flow_inits,
        move_data,
    };

    for bb in mir.basic_blocks().indices() {
        generator.add_liveness_constraints(bb);
    }
}

struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
where
    'typeck: 'gen,
    'flow: 'gen,
    'tcx: 'typeck + 'flow,
    'gcx: 'tcx,
{
    cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
    tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
    mir: &'gen Mir<'tcx>,
    liveness: &'gen LivenessResults,
    flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
    move_data: &'gen MoveData<'tcx>,
}

impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
    /// Liveness constraints:
    ///
    /// > If a variable V is live at point P, then all regions R in the type of V
    /// > must include the point P.
    fn add_liveness_constraints(&mut self, bb: BasicBlock) {
        debug!("add_liveness_constraints(bb={:?})", bb);

        self.liveness
            .regular
            .simulate_block(self.mir, bb, |location, live_locals| {
                for live_local in live_locals.iter() {
                    let live_local_ty = self.mir.local_decls[live_local].ty;
                    let cause = Cause::LiveVar(live_local, location);
                    self.push_type_live_constraint(live_local_ty, location, cause);
                }
            });

        let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
        self.liveness
            .drop
            .simulate_block(self.mir, bb, |location, live_locals| {
                all_live_locals.push((location, live_locals.iter().collect()));
            });
        debug!(
            "add_liveness_constraints: all_live_locals={:#?}",
            all_live_locals
        );

        let terminator_index = self.mir.basic_blocks()[bb].statements.len();
        self.flow_inits.reset_to_entry_of(bb);
        while let Some((location, live_locals)) = all_live_locals.pop() {
            for live_local in live_locals {
                debug!(
                    "add_liveness_constraints: location={:?} live_local={:?}",
                    location, live_local
                );

                if log_enabled!(::log::Level::Debug) {
                    self.flow_inits.each_state_bit(|mpi_init| {
                        debug!(
                            "add_liveness_constraints: location={:?} initialized={:?}",
                            location,
                            &self.flow_inits.operator().move_data().move_paths[mpi_init]
                        );
                    });
                }

                let mpi = self.move_data.rev_lookup.find_local(live_local);
                if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
                    debug!(
                        "add_liveness_constraints: mpi={:?} has initialized child {:?}",
                        self.move_data.move_paths[mpi],
                        self.move_data.move_paths[initialized_child]
                    );

                    let live_local_ty = self.mir.local_decls[live_local].ty;
                    self.add_drop_live_constraint(live_local, live_local_ty, location);
                }
            }

            if location.statement_index == terminator_index {
                debug!(
                    "add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
                    location
                );
                self.flow_inits.reconstruct_terminator_effect(location);
            } else {
                debug!(
                    "add_liveness_constraints: reconstruct_statement_effect from {:#?}",
                    location
                );
                self.flow_inits.reconstruct_statement_effect(location);
            }
            self.flow_inits.apply_local_effect(location);
        }
    }

    /// Some variable with type `live_ty` is "regular live" at
    /// `location` -- i.e., it may be used later. This means that all
    /// regions appearing in the type `live_ty` must be live at
    /// `location`.
    fn push_type_live_constraint<T>(&mut self, value: T, location: Location, cause: Cause)
    where
        T: TypeFoldable<'tcx>,
    {
        debug!(
            "push_type_live_constraint(live_ty={:?}, location={:?})",
            value, location
        );

        self.tcx.for_each_free_region(&value, |live_region| {
            self.cx
                .constraints
                .liveness_set
                .push((live_region, location, cause.clone()));
        });
    }

    /// Some variable with type `live_ty` is "drop live" at `location`
    /// -- i.e., it may be dropped later. This means that *some* of
    /// the regions in its type must be live at `location`. The
    /// precise set will depend on the dropck constraints, and in
    /// particular this takes `#[may_dangle]` into account.
    fn add_drop_live_constraint(
        &mut self,
        dropped_local: Local,
        dropped_ty: Ty<'tcx>,
        location: Location,
    ) {
        debug!(
            "add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})",
            dropped_local, dropped_ty, location
        );

        // If we end visiting the same type twice (usually due to a cycle involving
        // associated types), we need to ensure that its region types match up with the type
        // we added to the 'known' map the first time around. For this reason, we need
        // our infcx to hold onto its calculated region constraints after each call
        // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
        // type will end up instantiating the type with a new set of inference variables
        // Since this new type will never be in 'known', we end up looping forever.
        //
        // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
        // ourselves in one large 'fully_perform_op' callback.
        let kind_constraints = self.cx
            .fully_perform_op(location.at_self(), |cx| {
                let span = cx.last_span;

                let mut final_obligations = Vec::new();
                let mut kind_constraints = Vec::new();

                let InferOk {
                    value: kinds,
                    obligations,
                } = cx.infcx
                    .at(&cx.misc(span), cx.param_env)
                    .dropck_outlives(dropped_ty);
                for kind in kinds {
                    // All things in the `outlives` array may be touched by
                    // the destructor and must be live at this point.
                    let cause = Cause::DropVar(dropped_local, location);
                    kind_constraints.push((kind, location, cause));
                }

                final_obligations.extend(obligations);

                Ok(InferOk {
                    value: kind_constraints,
                    obligations: final_obligations,
                })
            })
            .unwrap();

        for (kind, location, cause) in kind_constraints {
            self.push_type_live_constraint(kind, location, cause);
        }
    }
}
<|endoftext|>


<commit_before>pub fn add_three_times_four(x: int) -> int {
    times_four(add_three(x))
}

fn add_three(x: int) -> int { x + 3 }

fn times_four(x: int) -> int { x * 4 }

#[cfg(test)]
mod test {
    use super::add_three;
    use super::times_four;

    #[test]
    fn test_add_three(){
        let result = add_three(5i);

        assert_eq!(8i, result);
    }

    #[test]
    fn test_times_four(){
        let result = times_four(5i);

        assert_eq!(20i, result);
    }
}
<commit_msg>fix types<commit_after>pub fn add_three_times_four(x: i32) -> i32 {
    times_four(add_three(x))
}

fn add_three(x: i32) -> i32 { x + 3 }

fn times_four(x: i32) -> i32 { x * 4 }

#[cfg(test)]
mod test {
    use super::add_three;
    use super::times_four;

    #[test]
    fn test_add_three(){
        let result = add_three(5i32);

        assert_eq!(8i32, result);
    }

    #[test]
    fn test_times_four(){
        let result = times_four(5i32);

        assert_eq!(20i32, result);
    }
}
<|endoftext|>


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

// Keybase Wallet Plugin

use controller;
use failure::ResultExt;
use libtx::slate::Slate;
use libwallet::{Error, ErrorKind};
use serde::Serialize;
use serde_json::{from_str, to_string, Value};
use std::collections::{HashMap, HashSet};
use std::process::{Command, Stdio};
use std::str::from_utf8;
use std::thread::sleep;
use std::time::{Duration, Instant};
use {instantiate_wallet, WalletCommAdapter, WalletConfig};

const TTL: u16 = 60; // TODO: Pass this as a parameter
const SLEEP_DURATION: Duration = Duration::from_millis(5000);

// Which topic names to use for communication
const SLATE_NEW: &str = "grin_slate_new";
const SLATE_SIGNED: &str = "grin_slate_signed";

#[derive(Clone)]
pub struct KeybaseWalletCommAdapter {}

impl KeybaseWalletCommAdapter {
	/// Check if keybase is installed and return an adapter object.
	pub fn new() -> Box<WalletCommAdapter> {
		let mut proc = if cfg!(target_os = "windows") {
			Command::new("where")
		} else {
			Command::new("which")
		};
		proc.arg("keybase")
			.stdout(Stdio::null())
			.status()
			.expect("Keybase executable not found, make sure it is installed and in your PATH");

		Box::new(KeybaseWalletCommAdapter {})
	}
}

/// Send a json object to the keybase process. Type `keybase chat api --help` for a list of available methods.
fn api_send(payload: &str) -> Value {
	let mut proc = Command::new("keybase");
	proc.args(&["chat", "api", "-m", &payload]);
	let output = proc.output().expect("No output").stdout;
	let response: Value = from_str(from_utf8(&output).expect("Bad output")).expect("Bad output");
	response
}

/// Get all unread messages from a specific channel/topic and mark as read.
fn read_from_channel(channel: &str, topic: &str) -> Vec<String> {
	let payload = to_string(&json!({
        "method": "read",
        "params": {
            "options": {
                "channel": {
                        "name": channel, "topic_type": "dev", "topic_name": topic
                    },
					"unread_only": true, "peek": false
                },
            }
        }
    )).unwrap();

	let response = api_send(&payload);
	let mut unread: Vec<String> = Vec::new();
	for msg in response["result"]["messages"]
		.as_array()
		.unwrap_or(&vec![json!({})])
		.iter()
	{
		if (msg["msg"]["content"]["type"] == "text") && (msg["msg"]["unread"] == true) {
			let message = msg["msg"]["content"]["text"]["body"].as_str().unwrap_or("");
			unread.push(message.to_owned());
		}
	}
	unread
}

/// Get unread messages from all channels and mark as read.
fn get_unread(topic: &str) -> HashMap<String, String> {
	let payload = to_string(&json!({
        "method": "list",
        "params": {
            "options": {
                    "topic_type": "dev",
                },
            }
        }
    )).unwrap();
	let response = api_send(&payload);

	let mut channels = HashSet::new();
	// Unfortunately the response does not contain the message body
	// and a seperate call is needed for each channel
	for msg in response["result"]["conversations"]
		.as_array()
		.unwrap_or(&vec![json!({})])
		.iter()
	{
		if (msg["unread"] == true) && (msg["channel"]["topic_name"] == topic) {
			let channel = msg["channel"]["name"].as_str().unwrap();
			channels.insert(channel.to_string());
		}
	}
	let mut unread: HashMap<String, String> = HashMap::new();
	for channel in channels.iter() {
		let messages = read_from_channel(channel, topic);
		for msg in messages {
			unread.insert(msg, channel.to_string());
		}
	}
	unread
}

/// Send a message to a keybase channel that self-destructs after ttl seconds.
fn send<T: Serialize>(message: T, channel: &str, topic: &str, ttl: u16) -> bool {
	let seconds = format!("{}s", ttl);
	let payload = to_string(&json!({
		"method": "send",
		"params": {
			"options": {
				"channel": {
						"name": channel, "topic_name": topic, "topic_type": "dev"
					},
						"message": {
								"body": to_string(&message).unwrap()
							},
							"exploding_lifetime": seconds
						}
					}
				}
	)).unwrap();
	let response = api_send(&payload);
	match response["result"]["message"].as_str() {
		Some("message sent") => true,
		_ => false,
	}
}

/// Listen for a message from a specific channel with topic SLATE_SIGNED for nseconds and return the first valid slate.
fn poll(nseconds: u64, channel: &str) -> Option<Slate> {
	let start = Instant::now();
	println!("Waiting for message from {}...", channel);
	while start.elapsed().as_secs() < nseconds {
		let unread = read_from_channel(channel, SLATE_SIGNED);
		for msg in unread.iter() {
			let blob = from_str::<Slate>(msg);
			match blob {
				Ok(slate) => {
					println!("Received message from {}", channel);
					return Some(slate);
				}
				Err(_) => (),
			}
		}
		sleep(SLEEP_DURATION);
	}
	println!(
		"Did not receive reply from {} in {} seconds",
		channel, nseconds
	);
	None
}

impl WalletCommAdapter for KeybaseWalletCommAdapter {
	fn supports_sync(&self) -> bool {
		true
	}

	// Send a slate to a keybase username then wait for a response for TTL seconds.
	fn send_tx_sync(&self, addr: &str, slate: &Slate) -> Result<Slate, Error> {
		// Send original slate to recipient with the SLATE_NEW topic
		match send(slate, addr, SLATE_NEW, TTL) {
			true => (),
			false => return Err(ErrorKind::ClientCallback("Posting transaction slate"))?,
		}
		println!("Sent new slate to {}", addr);
		// Wait for response from recipient with SLATE_SIGNED topic
		match poll(TTL as u64, addr) {
			Some(slate) => return Ok(slate),
			None => return Err(ErrorKind::ClientCallback("Receiving reply from recipient"))?,
		}
	}

	/// Send a transaction asynchronously (result will be returned via the listener)
	fn send_tx_async(&self, _addr: &str, _slate: &Slate) -> Result<(), Error> {
		unimplemented!();
	}

	/// Receive a transaction async. (Actually just read it from wherever and return the slate)
	fn receive_tx_async(&self, _params: &str) -> Result<Slate, Error> {
		unimplemented!();
	}

	/// Start a listener, passing received messages to the wallet api directly
	#[allow(unreachable_code)]
	fn listen(
		&self,
		_params: HashMap<String, String>,
		config: WalletConfig,
		passphrase: &str,
		account: &str,
		node_api_secret: Option<String>,
	) -> Result<(), Error> {
		let wallet =
			instantiate_wallet(config.clone(), passphrase, account, node_api_secret.clone())
				.context(ErrorKind::WalletSeedDecryption)?;

		println!("Listening for messages via keybase chat...");
		loop {
			// listen for messages from all channels with topic SLATE_NEW
			let unread = get_unread(SLATE_NEW);
			for (msg, channel) in &unread {
				let blob = from_str::<Slate>(msg);
				match blob {
					Ok(mut slate) => {
						println!("Received message from channel {}", channel);
						match controller::foreign_single_use(wallet.clone(), |api| {
							api.receive_tx(&mut slate, None, None)?;
							Ok(())
						}) {
							// Reply to the same channel with topic SLATE_SIGNED
							Ok(_) => match send(slate, channel, SLATE_SIGNED, TTL) {
								true => {
									println!("Returned slate to {}", channel);
								}
								false => {
									println!("Failed to return slate to {}", channel);
								}
							},
							Err(e) => {
								println!("Error : {}", e);
							}
						}
					}
					Err(_) => (),
				}
			}
			sleep(SLEEP_DURATION);
		}
		Ok(())
	}
}
<commit_msg>Keybase adapter merge issue fix (#2086)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Keybase Wallet Plugin

use controller;
use core::libtx::slate::Slate;
use failure::ResultExt;
use libwallet::{Error, ErrorKind};
use serde::Serialize;
use serde_json::{from_str, to_string, Value};
use std::collections::{HashMap, HashSet};
use std::process::{Command, Stdio};
use std::str::from_utf8;
use std::thread::sleep;
use std::time::{Duration, Instant};
use {instantiate_wallet, WalletCommAdapter, WalletConfig};

const TTL: u16 = 60; // TODO: Pass this as a parameter
const SLEEP_DURATION: Duration = Duration::from_millis(5000);

// Which topic names to use for communication
const SLATE_NEW: &str = "grin_slate_new";
const SLATE_SIGNED: &str = "grin_slate_signed";

#[derive(Clone)]
pub struct KeybaseWalletCommAdapter {}

impl KeybaseWalletCommAdapter {
	/// Check if keybase is installed and return an adapter object.
	pub fn new() -> Box<WalletCommAdapter> {
		let mut proc = if cfg!(target_os = "windows") {
			Command::new("where")
		} else {
			Command::new("which")
		};
		proc.arg("keybase")
			.stdout(Stdio::null())
			.status()
			.expect("Keybase executable not found, make sure it is installed and in your PATH");

		Box::new(KeybaseWalletCommAdapter {})
	}
}

/// Send a json object to the keybase process. Type `keybase chat api --help` for a list of available methods.
fn api_send(payload: &str) -> Value {
	let mut proc = Command::new("keybase");
	proc.args(&["chat", "api", "-m", &payload]);
	let output = proc.output().expect("No output").stdout;
	let response: Value = from_str(from_utf8(&output).expect("Bad output")).expect("Bad output");
	response
}

/// Get all unread messages from a specific channel/topic and mark as read.
fn read_from_channel(channel: &str, topic: &str) -> Vec<String> {
	let payload = to_string(&json!({
        "method": "read",
        "params": {
            "options": {
                "channel": {
                        "name": channel, "topic_type": "dev", "topic_name": topic
                    },
					"unread_only": true, "peek": false
                },
            }
        }
    )).unwrap();

	let response = api_send(&payload);
	let mut unread: Vec<String> = Vec::new();
	for msg in response["result"]["messages"]
		.as_array()
		.unwrap_or(&vec![json!({})])
		.iter()
	{
		if (msg["msg"]["content"]["type"] == "text") && (msg["msg"]["unread"] == true) {
			let message = msg["msg"]["content"]["text"]["body"].as_str().unwrap_or("");
			unread.push(message.to_owned());
		}
	}
	unread
}

/// Get unread messages from all channels and mark as read.
fn get_unread(topic: &str) -> HashMap<String, String> {
	let payload = to_string(&json!({
        "method": "list",
        "params": {
            "options": {
                    "topic_type": "dev",
                },
            }
        }
    )).unwrap();
	let response = api_send(&payload);

	let mut channels = HashSet::new();
	// Unfortunately the response does not contain the message body
	// and a seperate call is needed for each channel
	for msg in response["result"]["conversations"]
		.as_array()
		.unwrap_or(&vec![json!({})])
		.iter()
	{
		if (msg["unread"] == true) && (msg["channel"]["topic_name"] == topic) {
			let channel = msg["channel"]["name"].as_str().unwrap();
			channels.insert(channel.to_string());
		}
	}
	let mut unread: HashMap<String, String> = HashMap::new();
	for channel in channels.iter() {
		let messages = read_from_channel(channel, topic);
		for msg in messages {
			unread.insert(msg, channel.to_string());
		}
	}
	unread
}

/// Send a message to a keybase channel that self-destructs after ttl seconds.
fn send<T: Serialize>(message: T, channel: &str, topic: &str, ttl: u16) -> bool {
	let seconds = format!("{}s", ttl);
	let payload = to_string(&json!({
		"method": "send",
		"params": {
			"options": {
				"channel": {
						"name": channel, "topic_name": topic, "topic_type": "dev"
					},
						"message": {
								"body": to_string(&message).unwrap()
							},
							"exploding_lifetime": seconds
						}
					}
				}
	)).unwrap();
	let response = api_send(&payload);
	match response["result"]["message"].as_str() {
		Some("message sent") => true,
		_ => false,
	}
}

/// Listen for a message from a specific channel with topic SLATE_SIGNED for nseconds and return the first valid slate.
fn poll(nseconds: u64, channel: &str) -> Option<Slate> {
	let start = Instant::now();
	println!("Waiting for message from {}...", channel);
	while start.elapsed().as_secs() < nseconds {
		let unread = read_from_channel(channel, SLATE_SIGNED);
		for msg in unread.iter() {
			let blob = from_str::<Slate>(msg);
			match blob {
				Ok(slate) => {
					println!("Received message from {}", channel);
					return Some(slate);
				}
				Err(_) => (),
			}
		}
		sleep(SLEEP_DURATION);
	}
	println!(
		"Did not receive reply from {} in {} seconds",
		channel, nseconds
	);
	None
}

impl WalletCommAdapter for KeybaseWalletCommAdapter {
	fn supports_sync(&self) -> bool {
		true
	}

	// Send a slate to a keybase username then wait for a response for TTL seconds.
	fn send_tx_sync(&self, addr: &str, slate: &Slate) -> Result<Slate, Error> {
		// Send original slate to recipient with the SLATE_NEW topic
		match send(slate, addr, SLATE_NEW, TTL) {
			true => (),
			false => return Err(ErrorKind::ClientCallback("Posting transaction slate"))?,
		}
		println!("Sent new slate to {}", addr);
		// Wait for response from recipient with SLATE_SIGNED topic
		match poll(TTL as u64, addr) {
			Some(slate) => return Ok(slate),
			None => return Err(ErrorKind::ClientCallback("Receiving reply from recipient"))?,
		}
	}

	/// Send a transaction asynchronously (result will be returned via the listener)
	fn send_tx_async(&self, _addr: &str, _slate: &Slate) -> Result<(), Error> {
		unimplemented!();
	}

	/// Receive a transaction async. (Actually just read it from wherever and return the slate)
	fn receive_tx_async(&self, _params: &str) -> Result<Slate, Error> {
		unimplemented!();
	}

	/// Start a listener, passing received messages to the wallet api directly
	#[allow(unreachable_code)]
	fn listen(
		&self,
		_params: HashMap<String, String>,
		config: WalletConfig,
		passphrase: &str,
		account: &str,
		node_api_secret: Option<String>,
	) -> Result<(), Error> {
		let wallet =
			instantiate_wallet(config.clone(), passphrase, account, node_api_secret.clone())
				.context(ErrorKind::WalletSeedDecryption)?;

		println!("Listening for messages via keybase chat...");
		loop {
			// listen for messages from all channels with topic SLATE_NEW
			let unread = get_unread(SLATE_NEW);
			for (msg, channel) in &unread {
				let blob = from_str::<Slate>(msg);
				match blob {
					Ok(mut slate) => {
						println!("Received message from channel {}", channel);
						match controller::foreign_single_use(wallet.clone(), |api| {
							api.receive_tx(&mut slate, None, None)?;
							Ok(())
						}) {
							// Reply to the same channel with topic SLATE_SIGNED
							Ok(_) => match send(slate, channel, SLATE_SIGNED, TTL) {
								true => {
									println!("Returned slate to {}", channel);
								}
								false => {
									println!("Failed to return slate to {}", channel);
								}
							},
							Err(e) => {
								println!("Error : {}", e);
							}
						}
					}
					Err(_) => (),
				}
			}
			sleep(SLEEP_DURATION);
		}
		Ok(())
	}
}
<|endoftext|>


<commit_before>#[cfg(not(feature = "rustc-dep-of-std"))]
extern crate alloc;

use crate::{
	block_current_task, get_priority, getpid, set_priority, wakeup_task, yield_now, Priority, Tid,
	NO_PRIORITIES,
};
use alloc::collections::vec_deque::VecDeque;
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut, Drop};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{hint, mem};

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completely fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
	queue: AtomicUsize,
	dequeue: AtomicUsize,
	data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized> {
	dequeue: &'a AtomicUsize,
	data: &'a mut T,
}

impl<T> Spinlock<T> {
	pub const fn new(user_data: T) -> Spinlock<T> {
		Spinlock {
			queue: AtomicUsize::new(0),
			dequeue: AtomicUsize::new(1),
			data: UnsafeCell::new(user_data),
		}
	}

	#[inline]
	fn obtain_lock(&self) {
		let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
		let mut counter: u16 = 0;
		while self.dequeue.load(Ordering::SeqCst) != ticket {
			counter += 1;
			if counter < 100 {
				hint::spin_loop();
			} else {
				counter = 0;
				unsafe {
					yield_now();
				}
			}
		}
	}

	#[inline]
	pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
		self.obtain_lock();
		SpinlockGuard {
			dequeue: &self.dequeue,
			data: &mut *self.data.get(),
		}
	}
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
	fn default() -> Spinlock<T> {
		Spinlock::new(Default::default())
	}
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
	type Target = T;
	fn deref(&self) -> &T {
		&*self.data
	}
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
	fn deref_mut(&mut self) -> &mut T {
		&mut *self.data
	}
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
	/// The dropping of the SpinlockGuard will release the lock it was created from.
	fn drop(&mut self) {
		self.dequeue.fetch_add(1, Ordering::SeqCst);
	}
}

/// Realize a priority queue for tasks
struct PriorityQueue {
	queues: [Option<VecDeque<Tid>>; NO_PRIORITIES],
	prio_bitmap: u64,
}

impl PriorityQueue {
	pub const fn new() -> PriorityQueue {
		PriorityQueue {
			queues: [
				None, None, None, None, None, None, None, None, None, None, None, None, None, None,
				None, None, None, None, None, None, None, None, None, None, None, None, None, None,
				None, None, None,
			],
			prio_bitmap: 0,
		}
	}

	/// Add a task id by its priority to the queue
	pub fn push(&mut self, prio: Priority, id: Tid) {
		let i: usize = prio.into().into();
		self.prio_bitmap |= (1 << i) as u64;
		if let Some(queue) = &mut self.queues[i] {
			queue.push_back(id);
		} else {
			let mut queue = VecDeque::new();
			queue.push_back(id);
			self.queues[i] = Some(queue);
		}
	}

	fn pop_from_queue(&mut self, queue_index: usize) -> Option<Tid> {
		if let Some(queue) = &mut self.queues[queue_index] {
			let id = queue.pop_front();

			if queue.is_empty() {
				self.prio_bitmap &= !(1 << queue_index as u64);
			}

			id
		} else {
			None
		}
	}

	/// Pop the task handle with the highest priority from the queue
	pub fn pop(&mut self) -> Option<Tid> {
		for i in 0..NO_PRIORITIES {
			if self.prio_bitmap & (1 << i) != 0 {
				return self.pop_from_queue(i);
			}
		}

		None
	}
}

enum MutexState {
	Unlocked,
	Locked {
		/// Identifies the task.
		id: Tid,
		/// Current priority of the task, which holds the lock
		current_prio: Priority,
		/// Original priority of the task, which holds the lock
		base_prio: Priority,
	},
}

struct MutexInner {
	state: MutexState,
	/// Priority queue of blocked tasks
	blocked_tasks: PriorityQueue,
}

impl MutexInner {
	pub const fn new() -> MutexInner {
		Self {
			state: MutexState::Unlocked,
			blocked_tasks: PriorityQueue::new(),
		}
	}
}

pub struct Mutex {
	inner: Spinlock<MutexInner>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
	pub const fn new() -> Mutex {
		Mutex {
			inner: Spinlock::new(MutexInner::new()),
		}
	}

	#[inline]
	pub unsafe fn init(&mut self) {
		self.inner = Spinlock::new(MutexInner::new());
	}

	#[inline]
	pub unsafe fn lock(&self) {
		loop {
			let mut guard = self.inner.lock();
			match guard.state {
				MutexState::Unlocked => {
					let prio = get_priority();
					guard.state = MutexState::Locked {
						id: getpid(),
						current_prio: prio,
						base_prio: prio,
					};
					return;
				}
				MutexState::Locked {
					id,
					ref mut current_prio,
					base_prio: _,
				} => {
					let prio = get_priority();

					if *current_prio < prio {
						set_priority(id, prio);
						*current_prio = prio;
					}
					guard.blocked_tasks.push(prio, getpid());
					block_current_task();
					drop(guard);
					yield_now();
				}
			}
		}
	}

	#[inline]
	pub unsafe fn unlock(&self) {
		let mut guard = self.inner.lock();

		if let MutexState::Locked {
			id,
			current_prio,
			base_prio,
		} = mem::replace(&mut guard.state, MutexState::Unlocked)
		{
			if current_prio != base_prio {
				set_priority(id, base_prio);
			}

			guard.state = MutexState::Unlocked;

			if let Some(tid) = guard.blocked_tasks.pop() {
				wakeup_task(tid);
			}
		}
	}

	#[inline]
	pub unsafe fn try_lock(&self) -> bool {
		let mut guard = self.inner.lock();

		if matches!(guard.state, MutexState::Unlocked) {
			let prio = get_priority();
			guard.state = MutexState::Locked {
				id: getpid(),
				current_prio: prio,
				base_prio: prio,
			};

			true
		} else {
			false
		}
	}

	#[inline]
	pub unsafe fn destroy(&self) {}
}
<commit_msg>add try_lock support for spinlock<commit_after>#[cfg(not(feature = "rustc-dep-of-std"))]
extern crate alloc;

use crate::{
	block_current_task, get_priority, getpid, wakeup_task, yield_now, Priority, Tid, NO_PRIORITIES,
};
use alloc::collections::vec_deque::VecDeque;
use core::cell::UnsafeCell;
use core::hint;
use core::ops::{Deref, DerefMut, Drop};
use core::sync::atomic::{AtomicBool, Ordering};

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completely fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
	inner: AtomicBool,
	data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized> {
	inner: &'a AtomicBool,
	data: &'a mut T,
}

impl<T> Spinlock<T> {
	pub const fn new(user_data: T) -> Spinlock<T> {
		Spinlock {
			inner: AtomicBool::new(false),
			data: UnsafeCell::new(user_data),
		}
	}

	#[inline]
	fn obtain_lock(&self) {
		let mut counter: u16 = 0;
		while self.inner.swap(true, Ordering::SeqCst) {
			counter += 1;
			if counter < 100 {
				hint::spin_loop();
			} else {
				counter = 0;
				unsafe {
					yield_now();
				}
			}
		}
	}

	#[inline]
	fn try_obtain_lock(&self) -> bool {
		!self.inner.swap(true, Ordering::SeqCst)
	}

	#[inline]
	pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
		self.obtain_lock();
		SpinlockGuard {
			inner: &self.inner,
			data: &mut *self.data.get(),
		}
	}

	#[inline]
	pub unsafe fn try_lock(&self) -> Result<SpinlockGuard<'_, T>, ()> {
		if self.try_obtain_lock() {
			Ok(SpinlockGuard {
				inner: &self.inner,
				data: &mut *self.data.get(),
			})
		} else {
			Err(())
		}
	}
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
	fn default() -> Spinlock<T> {
		Spinlock::new(Default::default())
	}
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
	type Target = T;
	fn deref(&self) -> &T {
		&*self.data
	}
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
	fn deref_mut(&mut self) -> &mut T {
		&mut *self.data
	}
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
	/// The dropping of the SpinlockGuard will release the lock it was created from.
	fn drop(&mut self) {
		self.inner.swap(false, Ordering::SeqCst);
	}
}

/// Realize a priority queue for tasks
struct PriorityQueue {
	queues: [Option<VecDeque<Tid>>; NO_PRIORITIES],
	prio_bitmap: u64,
}

impl PriorityQueue {
	pub const fn new() -> PriorityQueue {
		PriorityQueue {
			queues: [
				None, None, None, None, None, None, None, None, None, None, None, None, None, None,
				None, None, None, None, None, None, None, None, None, None, None, None, None, None,
				None, None, None,
			],
			prio_bitmap: 0,
		}
	}

	/// Add a task id by its priority to the queue
	pub fn push(&mut self, prio: Priority, id: Tid) {
		let i: usize = prio.into().into();
		self.prio_bitmap |= (1 << i) as u64;
		if let Some(queue) = &mut self.queues[i] {
			queue.push_back(id);
		} else {
			let mut queue = VecDeque::new();
			queue.push_back(id);
			self.queues[i] = Some(queue);
		}
	}

	fn pop_from_queue(&mut self, queue_index: usize) -> Option<Tid> {
		if let Some(queue) = &mut self.queues[queue_index] {
			let id = queue.pop_front();

			if queue.is_empty() {
				self.prio_bitmap &= !(1 << queue_index as u64);
			}

			id
		} else {
			None
		}
	}

	/// Pop the task handle with the highest priority from the queue
	pub fn pop(&mut self) -> Option<Tid> {
		for i in 0..NO_PRIORITIES {
			if self.prio_bitmap & (1 << i) != 0 {
				return self.pop_from_queue(i);
			}
		}

		None
	}
}

struct MutexInner {
	locked: bool,
	/// Priority queue of blocked tasks
	blocked_tasks: PriorityQueue,
}

impl MutexInner {
	pub const fn new() -> MutexInner {
		Self {
			locked: false,
			blocked_tasks: PriorityQueue::new(),
		}
	}
}

pub struct Mutex {
	inner: Spinlock<MutexInner>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
	pub const fn new() -> Mutex {
		Mutex {
			inner: Spinlock::new(MutexInner::new()),
		}
	}

	#[inline]
	pub unsafe fn lock(&self) {
		loop {
			let mut guard = self.inner.lock();
			if !guard.locked {
				guard.locked = true;
				return;
			} else {
				let prio = get_priority();
				let id = getpid();

				guard.blocked_tasks.push(prio, id);
				block_current_task();
				drop(guard);
				yield_now();
			}
		}
	}

	#[inline]
	pub unsafe fn unlock(&self) {
		let mut guard = self.inner.lock();
		guard.locked = false;
		if let Some(tid) = guard.blocked_tasks.pop() {
			wakeup_task(tid);
		}
	}

	#[inline]
	pub unsafe fn try_lock(&self) -> bool {
		if let Ok(mut guard) = self.inner.try_lock() {
			if !guard.locked {
				guard.locked = true;

				true
			} else {
				false
			}
		} else {
			false
		}
	}
}
<|endoftext|>


<commit_before>use crate::utils::{in_macro, snippet, span_lint_and_sugg};
use hir::def::{DefKind, Res};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{edition::Edition, Span};

declare_clippy_lint! {
    /// **What it does:** Checks for `#[macro_use] use...`.
    ///
    /// **Why is this bad?** Since the Rust 2018 edition you can import
    /// macro's directly, this is considered idiomatic.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// #[macro_use]
    /// use lazy_static;
    /// ```
    pub MACRO_USE_IMPORTS,
    pedantic,
    "#[macro_use] is no longer needed"
}

const BRACKETS: &[char] = &['<', '>'];

/// `MacroRefData` includes the name of the macro
/// and the path from `SourceMap::span_to_filename`.
#[derive(Debug, Clone)]
pub struct MacroRefData {
    name: String,
    path: String,
}

impl MacroRefData {
    pub fn new(name: &str, callee: Span, cx: &LateContext<'_, '_>) -> Self {
        let mut path = cx.sess().source_map().span_to_filename(callee).to_string();

        // std lib paths are <::std::module::file type>
        // so remove brackets, space and type.
        if path.contains('<') {
            path = path.replace(BRACKETS, "");
        }
        if path.contains(' ') {
            path = path.split(' ').next().unwrap().to_string();
        }
        Self {
            name: name.to_string(),
            path,
        }
    }
}

#[derive(Default)]
#[allow(clippy::module_name_repetitions)]
pub struct MacroUseImports {
    /// the actual import path used and the span of the attribute above it.
    imports: Vec<(String, Span)>,
    /// the span of the macro reference, kept to ensure only one reference is used per macro call.
    collected: FxHashSet<Span>,
    mac_refs: Vec<MacroRefData>,
}

impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);

impl MacroUseImports {
    fn push_unique_macro(&mut self, cx: &LateContext<'_, '_>, name: &str, call_site: Span, callee: Span) {
        if !self.collected.contains(&call_site) {
            let name = if name.contains("::") {
                name.split("::").last().unwrap().to_string()
            } else {
                name.to_string()
            };

            self.mac_refs.push(MacroRefData::new(&name, callee, cx));
            self.collected.insert(call_site);
        }
    }

    fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_, '_>, name: &str, call_site: Span, callee: Span) {
        if !self.collected.contains(&call_site) {
            self.mac_refs.push(MacroRefData::new(&name, callee, cx));
            self.collected.insert(call_site);
        }
    }
}

impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
        if_chain! {
                if cx.sess().opts.edition == Edition::Edition2018;
                if let hir::ItemKind::Use(path, _kind) = &item.kind;
                if let Some(mac_attr) = item
                    .attrs
                    .iter()
                    .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
                if let Res::Def(DefKind::Mod, id) = path.res;
                then {
                    for kid in cx.tcx.item_children(id).iter() {
                        if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
                            let span = mac_attr.span;
                            self.imports.push((cx.tcx.def_path_str(mac_id), span));
                        }
                    }
                } else {
                    if in_macro(item.span) {
                        let call_site = item.span.source_callsite();
                        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
                        if let Some(callee) = item.span.source_callee() {
                            if !self.collected.contains(&call_site) {
                                self.mac_refs.push(MacroRefData::new(&name, callee.def_site, cx));
                                self.collected.insert(call_site);
                            }
                        }
                    }
            }
        }
    }
    fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
        if in_macro(attr.span) {
            let call_site = attr.span.source_callsite();
            let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
            if let Some(callee) = attr.span.source_callee() {
                self.push_unique_macro(cx, &name, call_site, callee.def_site);
            }
        }
    }
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
        if in_macro(expr.span) {
            let call_site = expr.span.source_callsite();
            let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
            if let Some(callee) = expr.span.source_callee() {
                self.push_unique_macro(cx, &name, call_site, callee.def_site);
            }
        }
    }
    fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>) {
        if in_macro(stmt.span) {
            let call_site = stmt.span.source_callsite();
            let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
            if let Some(callee) = stmt.span.source_callee() {
                self.push_unique_macro(cx, &name, call_site, callee.def_site);
            }
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
        if in_macro(pat.span) {
            let call_site = pat.span.source_callsite();
            let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
            if let Some(callee) = pat.span.source_callee() {
                self.push_unique_macro_pat_ty(cx, &name, call_site, callee.def_site);
            }
        }
    }
    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &hir::Ty<'_>) {
        if in_macro(ty.span) {
            let call_site = ty.span.source_callsite();
            let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
            if let Some(callee) = ty.span.source_callee() {
                self.push_unique_macro_pat_ty(cx, &name, call_site, callee.def_site);
            }
        }
    }

    fn check_crate_post(&mut self, cx: &LateContext<'_, '_>, _krate: &hir::Crate<'_>) {
        for (import, span) in &self.imports {
            let matched = self.mac_refs.iter().any(|mac| import.ends_with(&mac.name));

            if matched {
                self.mac_refs.retain(|mac| !import.ends_with(&mac.name));
                let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition";
                let help = format!("use {}", import);
                span_lint_and_sugg(
                    cx,
                    MACRO_USE_IMPORTS,
                    *span,
                    msg,
                    "remove the attribute and import the macro directly, try",
                    help,
                    Applicability::MaybeIncorrect,
                )
            }
        }
        if !self.mac_refs.is_empty() {
            // TODO if not empty we found one we could not make a suggestion for
            // such as std::prelude::v1 or something else I haven't thought of.
            // If we defer the calling of span_lint_and_sugg we can make a decision about its
            // applicability?
        }
    }
}
<commit_msg>still working on displaying nested imports<commit_after>use crate::utils::{in_macro, snippet, span_lint_and_sugg};
use hir::def::{DefKind, Res};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{edition::Edition, Span};

declare_clippy_lint! {
    /// **What it does:** Checks for `#[macro_use] use...`.
    ///
    /// **Why is this bad?** Since the Rust 2018 edition you can import
    /// macro's directly, this is considered idiomatic.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// #[macro_use]
    /// use lazy_static;
    /// ```
    pub MACRO_USE_IMPORTS,
    pedantic,
    "#[macro_use] is no longer needed"
}

const BRACKETS: &[char] = &['<', '>'];

/// `MacroRefData` includes the name of the macro
/// and the path from `SourceMap::span_to_filename`.
#[derive(Debug, Clone)]
pub struct MacroRefData {
    name: String,
    path: String,
}

impl MacroRefData {
    pub fn new(name: String, callee: Span, cx: &LateContext<'_, '_>) -> Self {
        let mut path = cx.sess().source_map().span_to_filename(callee).to_string();

        // std lib paths are <::std::module::file type>
        // so remove brackets, space and type.
        if path.contains('<') {
            path = path.replace(BRACKETS, "");
        }
        if path.contains(' ') {
            path = path.split(' ').next().unwrap().to_string();
        }
        Self {
            name,
            path,
        }
    }
}

#[derive(Default)]
#[allow(clippy::module_name_repetitions)]
pub struct MacroUseImports {
    /// the actual import path used and the span of the attribute above it.
    imports: Vec<(String, Span)>,
    /// the span of the macro reference, kept to ensure only one reference is used per macro call.
    collected: FxHashSet<Span>,
    mac_refs: Vec<MacroRefData>,
}

impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);

impl MacroUseImports {
    fn push_unique_macro(&mut self, cx: &LateContext<'_, '_>, span: Span) {
        let call_site = span.source_callsite();
        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
        if let Some(callee) = span.source_callee() {
            if !self.collected.contains(&call_site) {
                let name = if name.contains("::") {
                    name.split("::").last().unwrap().to_string()
                } else {
                    name.to_string()
                };

                self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx));
                self.collected.insert(call_site);
            }
        }
    }

    fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_, '_>, span: Span) {
        let call_site = span.source_callsite();
        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
        if let Some(callee) = span.source_callee() {
            if !self.collected.contains(&call_site) {
                self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
                self.collected.insert(call_site);
            }
        }
    }
}

impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
        if_chain! {
            if cx.sess().opts.edition == Edition::Edition2018;
            if let hir::ItemKind::Use(path, _kind) = &item.kind;
            if let Some(mac_attr) = item
                .attrs
                .iter()
                .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
            if let Res::Def(DefKind::Mod, id) = path.res;
            then {
                for kid in cx.tcx.item_children(id).iter() {
                    if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
                        let span = mac_attr.span;
                        self.imports.push((cx.tcx.def_path_str(mac_id), span));
                    }
                }
            } else {
                if in_macro(item.span) {
                    self.push_unique_macro_pat_ty(cx, item.span);
                }
            }
        }
    }
    fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
        if in_macro(attr.span) {
            self.push_unique_macro(cx, attr.span);
        }
    }
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
        if in_macro(expr.span) {
            self.push_unique_macro(cx, expr.span);
        }
    }
    fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>) {
        if in_macro(stmt.span) {
            self.push_unique_macro(cx, stmt.span);
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
        if in_macro(pat.span) {
            self.push_unique_macro_pat_ty(cx, pat.span);
        }
    }
    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &hir::Ty<'_>) {
        if in_macro(ty.span) {
            self.push_unique_macro_pat_ty(cx, ty.span);
        }
    }

    fn check_crate_post(&mut self, cx: &LateContext<'_, '_>, _krate: &hir::Crate<'_>) {
        let mut import_map = FxHashMap::default();
        for (import, span) in &self.imports {
            let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));

            if let Some(idx) = found_idx {
                let _ = self.mac_refs.remove(idx);
                proccess_macro_path(*span, import, &mut import_map);
            }
        }
        println!("{:#?}", import_map);
        let mut imports = vec![];
        for (root, rest) in import_map {
            let mut path = format!("use {}::", root);
            let mut s = None;
            let mut count = 1;
            let rest_len = rest.len();
            if rest_len > 1 {
                path.push_str("{");
            }
            for m in &rest {
                println!("{} => {:?}", root, m);
                if count == 1 {
                    s = Some(m.span());
                }

                let comma = if rest_len == count { "" } else { ", " };
                match m {
                    ModPath::Item { item, .. } => {
                        path.push_str(&format!("{}{}", item, comma));
                    }
                    ModPath::Nested { names, item, span } => {
                        let nested = rest.iter()
                            // filter "self" out
                            .filter(|other_m| other_m != &m)
                            // this matches the first path segment and filters non ModPath::Nested items
                            .filter(|other_m| other_m.matches(0, m))
                            .collect::<Vec<_>>();

                        println!("{:#?}", nested);

                        if nested.is_empty() {
                            path.push_str(&format!("{}::{}{}", names.join("::").to_string(), item, comma))
                        } else {
                            // use mod_a::{mod_b::{one, two}, mod_c::item, item1, item2}
                            let mod_path = if names.len() - 1 > 0 {
                                ModPath::Nested { names: names.clone(), item: item.to_string(), span: *span, }
                            } else {
                                ModPath::Item { item: names[0].to_string(), span: *span, }
                            };
                            let names = recursive_path_push(mod_path, comma, &rest, String::new());
                            path.push_str(&format!("{}::{{{}}}{}", names, item, comma))
                        }
                    }
                }
                count += 1;
            }
            if rest_len > 1 {
                path.push_str("};");
            }
            if let Some(span) = s {
                imports.push((span, path))
            }
        }

        if !self.mac_refs.is_empty() {
            // TODO if not empty we found one we could not make a suggestion for
            // such as std::prelude::v1 or something else I haven't thought of.
            // If we defer the calling of span_lint_and_sugg we can make a decision about its
            // applicability?
        } else {
            for (span, import) in imports {
                let help = format!("use {}", import);
                span_lint_and_sugg(
                    cx,
                    MACRO_USE_IMPORTS,
                    span,
                    "`macro_use` attributes are no longer needed in the Rust 2018 edition",
                    "remove the attribute and import the macro directly, try",
                    help,
                    Applicability::MaybeIncorrect,
                )
            }
        }
    }
}

#[derive(Debug, PartialEq)]
enum ModPath {
    Item { item: String, span: Span, },
    Nested { names: Vec<String>, item: String, span: Span, },
}

impl ModPath {
    fn span(&self) -> Span {
        match self {
            Self::Item { span, .. } => *span,
            Self::Nested { span, .. } => *span,
        }
    }

    fn item(&self) -> &str {
        match self {
            Self::Item { item, .. } => item,
            Self::Nested { item, .. } => item,
        }
    }

    fn matches(&self, idx: usize, other: &ModPath) -> bool {
        match (self, other) {
            (Self::Item { item, .. }, Self::Item { item: other_item, .. }) => item == other_item,
            (Self::Nested { names, .. }, Self::Nested { names: other_names, .. }) => {
                match (names.get(idx), other_names.get(idx)) {
                    (Some(seg), Some(other_seg)) => seg == other_seg,
                    (_, _) => false,
                }
            }
            (_, _) => false,
        }
    }
}

fn proccess_macro_path(span: Span, import: &str, import_map: &mut FxHashMap<String, Vec<ModPath>>) {
    let mut mod_path = import.split("::").collect::<Vec<_>>();

    if mod_path.len() == 2 {
        let item_list = import_map.entry(mod_path[0].to_string())
            .or_insert(vec![]);

        if !item_list.iter().any(|mods| mods.item() == mod_path[1]) {
            item_list.push(ModPath::Item{
                item: mod_path[1].to_string(),
                span,
            });
        }
    } else if mod_path.len() > 2 {
        let first = mod_path.remove(0);
        let name = mod_path.remove(mod_path.len() - 1);

        let nested = ModPath::Nested {
            names: mod_path.into_iter().map(ToString::to_string).collect(),
            item: name.to_string(),
            span,
        };
        import_map.entry(first.to_string())
            .or_insert(vec![])
            .push(nested);
    } else {
        unreachable!("test to see if code path hit TODO REMOVE")
    }
}

fn recursive_path_push(module: ModPath, comma: &str, rest: &[ModPath], mut path: String) -> String {
    match &module {
        ModPath::Item { item, .. } => {
            path.push_str(&format!("{}{}", item, comma));
        }
        ModPath::Nested { names, item, span } => {
            let nested = rest.iter()
                // filter "self" out
                .filter(|other_m| other_m != &&module)
                // this matches the first path segment and filters non ModPath::Nested items
                .filter(|other_m| other_m.matches(0, &module))
                .collect::<Vec<_>>();

            println!("{:#?}", nested);

            if nested.is_empty() {
                path.push_str(&format!("{}::{}{}", names.join("::").to_string(), item, comma))
            } else {
                // use mod_a::{mod_b::{one, two}, mod_c::item, item1, item2}
                let mod_path = if names.len() - 1 > 0 {
                    ModPath::Nested { names: names.clone(), item: item.to_string(), span: *span, }
                } else {
                    ModPath::Item { item: names[0].to_string(), span: *span, }
                };
                let names = recursive_path_push(mod_path, comma, rest, path.to_string());
                // path.push_str(&format!("{}{}", item, comma));
            }
        }
    }
    path
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use backtrace::Backtrace;
use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Metadata {
    /// The level of verbosity of the event
    level: Level,

    /// The part of the system where the event occurred
    target: &'static str,

    /// The name of the Rust module where the event occurred
    module_path: &'static str,

    /// The name of the source code file where the event occurred
    file: &'static str,

    /// The line number in the source code file where the event occurred
    line: u32,

    /// The file name and line number together 'file:line'
    location: &'static str,

    /// The program backtrace taken when the event occurred. Backtraces are
    /// only supported for errors.
    backtrace: Option<Backtrace>,
}

impl Metadata {
    pub fn new(
        level: Level,
        target: &'static str,
        module_path: &'static str,
        file: &'static str,
        line: u32,
        location: &'static str,
    ) -> Self {
        let backtrace = match level {
            Level::Error => {
                let backtrace = Backtrace::new();
                let mut frames = backtrace.frames().to_vec();
                if frames.len() > 3 {
                    frames.drain(0..3); // Remove the first 3 unnecessary frames to simplify backtrace
                }
                Some(frames.into())
            }
            _ => None,
        };

        Self {
            level,
            target,
            module_path,
            file,
            line,
            location,
            backtrace,
        }
    }

    pub fn enabled(&self) -> bool {
        crate::logger::enabled(self)
    }

    pub fn level(&self) -> Level {
        self.level
    }

    pub fn target(&self) -> &'static str {
        self.target
    }

    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    pub fn file(&self) -> &'static str {
        self.file
    }

    pub fn line(&self) -> u32 {
        self.line
    }

    pub fn location(&self) -> &'static str {
        self.location
    }

    pub fn backtrace(&self) -> Option<Backtrace> {
        self.backtrace.clone()
    }
}

static LOG_LEVEL_NAMES: &[&str] = &["ERROR", "WARN", "INFO", "DEBUG", "TRACE"];

#[repr(usize)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum Level {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 0,
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

impl Level {
    fn from_usize(idx: usize) -> Option<Self> {
        let lvl = match idx {
            0 => Level::Error,
            1 => Level::Warn,
            2 => Level::Info,
            3 => Level::Debug,
            4 => Level::Trace,
            _ => return None,
        };

        Some(lvl)
    }
}

#[derive(Debug)]
pub struct LevelParseError;

impl FromStr for Level {
    type Err = LevelParseError;
    fn from_str(level: &str) -> Result<Level, Self::Err> {
        LOG_LEVEL_NAMES
            .iter()
            .position(|name| name.eq_ignore_ascii_case(level))
            .map(|idx| Level::from_usize(idx).unwrap())
            .ok_or(LevelParseError)
    }
}

impl fmt::Display for Level {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad(LOG_LEVEL_NAMES[*self as usize])
    }
}
<commit_msg>[Logger] Format backtraces into strings to avoid auto-serialization.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use backtrace::Backtrace;
use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Metadata {
    /// The level of verbosity of the event
    level: Level,

    /// The part of the system where the event occurred
    target: &'static str,

    /// The name of the Rust module where the event occurred
    module_path: &'static str,

    /// The name of the source code file where the event occurred
    file: &'static str,

    /// The line number in the source code file where the event occurred
    line: u32,

    /// The file name and line number together 'file:line'
    location: &'static str,

    /// The program backtrace taken when the event occurred. Backtraces are
    /// only supported for errors.
    backtrace: Option<String>,
}

impl Metadata {
    pub fn new(
        level: Level,
        target: &'static str,
        module_path: &'static str,
        file: &'static str,
        line: u32,
        location: &'static str,
    ) -> Self {
        let backtrace = match level {
            Level::Error => {
                let mut backtrace = Backtrace::new();
                let mut frames = backtrace.frames().to_vec();
                if frames.len() > 3 {
                    frames.drain(0..3); // Remove the first 3 unnecessary frames to simplify backtrace
                }
                backtrace = frames.into();
                Some(format!("{:?}", backtrace))
            }
            _ => None,
        };

        Self {
            level,
            target,
            module_path,
            file,
            line,
            location,
            backtrace,
        }
    }

    pub fn enabled(&self) -> bool {
        crate::logger::enabled(self)
    }

    pub fn level(&self) -> Level {
        self.level
    }

    pub fn target(&self) -> &'static str {
        self.target
    }

    pub fn module_path(&self) -> &'static str {
        self.module_path
    }

    pub fn file(&self) -> &'static str {
        self.file
    }

    pub fn line(&self) -> u32 {
        self.line
    }

    pub fn location(&self) -> &'static str {
        self.location
    }

    pub fn backtrace(&self) -> Option<&str> {
        self.backtrace.as_deref()
    }
}

static LOG_LEVEL_NAMES: &[&str] = &["ERROR", "WARN", "INFO", "DEBUG", "TRACE"];

#[repr(usize)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum Level {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 0,
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

impl Level {
    fn from_usize(idx: usize) -> Option<Self> {
        let lvl = match idx {
            0 => Level::Error,
            1 => Level::Warn,
            2 => Level::Info,
            3 => Level::Debug,
            4 => Level::Trace,
            _ => return None,
        };

        Some(lvl)
    }
}

#[derive(Debug)]
pub struct LevelParseError;

impl FromStr for Level {
    type Err = LevelParseError;
    fn from_str(level: &str) -> Result<Level, Self::Err> {
        LOG_LEVEL_NAMES
            .iter()
            .position(|name| name.eq_ignore_ascii_case(level))
            .map(|idx| Level::from_usize(idx).unwrap())
            .ok_or(LevelParseError)
    }
}

impl fmt::Display for Level {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad(LOG_LEVEL_NAMES[*self as usize])
    }
}
<|endoftext|>


<commit_before>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/master/README.md).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may can be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//!   path is interpreted as relative to the `templates` dir in the directory
//!   where the originating crate's `Cargo.toml` resides. In web framework
//!   integrations, the path's extension may be used to infer the content type
//!   of the resulting response. Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//!   This can be useful for test cases or short templates. The generated path
//!   is empty, which generally makes it impossible to refer to this template
//!   from other templates. Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the template extension for
//!   use in web framework integrations. Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//!   (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//!   or `all` for both. The requested data will be printed to stdout at
//!   compile time.
//! * `escape` (as `escape = "none"`): disable escaping of expression output.
//!   By default, Askama escapes `&`, `<` and `>` to their corresponding
//!   HTML character entities. This can be enabled explicitly by setting this
//!   value to `html` or disabled by setting it to `none`.
//!
//! ## Variables
//!
//! Top-level template variables are defined by the template's context type.
//! You can use a dot (`.`) to access variable's attributes or methods.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field from the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that a single trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//! A base template must define one or more blocks in order to be enable
//! inheritance. Blocks can only be specified at the top level of a template,
//! not inside `if`/`else` branches or in `for`-loop bodies.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will search for the base template relative to
//! itself before looking relative to the template base directory. It will
//! render the top-level content from the base template, and substitute
//! blocks from the base template with those from the child template. The
//! inheriting template context `struct` must have a field called `_parent` of
//! the type used as the base template context. Blocks can refer to the context
//! of both parent and child template.
//!
//! Note that, if the base template lives in another module than the child
//! template, the child template's module should import all symbols from the
//! base template's module in order for it to find the trait definition that
//! supports the inheritance mechanism.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ### Include
//!
//! The *include* statement lets you split large or repetitive blocks into
//! separate template files. Included templates get full access to the context
//! in which they're used, including local variables like those from loops:
//!
//! ```text
//! {% for i in iter %}
//!   {% include "item.html" %}
//! {% endfor %}
//! ```
//!
//! ```text
//! * Item: {{ i }}
//! ```
//!
//! The path to include must be a string literal, so that it is known at
//! compile time. Askama will try to find the specified template relative
//! to the including template's path before falling back to the absolute
//! template path. Use `include` within the branches of an `if`/`else`
//! block to use includes more dynamically.
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The parser applies the same precedence order as the Rust compiler.
//! Expressions can be grouped using parentheses.
//! The HTML special characters `&`, `<` and `>` will be replaced with their
//! character entities unless the `escape` mode is disabled for a template.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;
extern crate askama_shared as shared;

use shared::path;

use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut std::fmt::Write) -> Result<()>;
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::new();
        self.render_into(&mut buf)?;
        Ok(buf)
    }
}

pub use shared::filters;
pub use askama_derive::*;
pub use shared::{Error, MarkupDisplay, Result};

#[cfg(feature = "with-iron")]
pub mod iron {
    extern crate iron;
    pub use self::iron::modifier::Modifier;
    pub use self::iron::response::Response;
}

#[cfg(feature = "with-rocket")]
pub mod rocket {
    extern crate rocket;
    pub use self::rocket::http::{ContentType, Status};
    pub use self::rocket::request::Request;
    pub use self::rocket::response::{Responder, Response};
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&path::template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<commit_msg>Add documentation on optional features<commit_after>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/master/README.md).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may can be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//!   path is interpreted as relative to the `templates` dir in the directory
//!   where the originating crate's `Cargo.toml` resides. In web framework
//!   integrations, the path's extension may be used to infer the content type
//!   of the resulting response. Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//!   This can be useful for test cases or short templates. The generated path
//!   is empty, which generally makes it impossible to refer to this template
//!   from other templates. Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the template extension for
//!   use in web framework integrations. Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//!   (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//!   or `all` for both. The requested data will be printed to stdout at
//!   compile time.
//! * `escape` (as `escape = "none"`): disable escaping of expression output.
//!   By default, Askama escapes `&`, `<` and `>` to their corresponding
//!   HTML character entities. This can be enabled explicitly by setting this
//!   value to `html` or disabled by setting it to `none`.
//!
//! ## Variables
//!
//! Top-level template variables are defined by the template's context type.
//! You can use a dot (`.`) to access variable's attributes or methods.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field from the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that a single trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//! A base template must define one or more blocks in order to be enable
//! inheritance. Blocks can only be specified at the top level of a template,
//! not inside `if`/`else` branches or in `for`-loop bodies.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will search for the base template relative to
//! itself before looking relative to the template base directory. It will
//! render the top-level content from the base template, and substitute
//! blocks from the base template with those from the child template. The
//! inheriting template context `struct` must have a field called `_parent` of
//! the type used as the base template context. Blocks can refer to the context
//! of both parent and child template.
//!
//! Note that, if the base template lives in another module than the child
//! template, the child template's module should import all symbols from the
//! base template's module in order for it to find the trait definition that
//! supports the inheritance mechanism.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ### Include
//!
//! The *include* statement lets you split large or repetitive blocks into
//! separate template files. Included templates get full access to the context
//! in which they're used, including local variables like those from loops:
//!
//! ```text
//! {% for i in iter %}
//!   {% include "item.html" %}
//! {% endfor %}
//! ```
//!
//! ```text
//! * Item: {{ i }}
//! ```
//!
//! The path to include must be a string literal, so that it is known at
//! compile time. Askama will try to find the specified template relative
//! to the including template's path before falling back to the absolute
//! template path. Use `include` within the branches of an `if`/`else`
//! block to use includes more dynamically.
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The parser applies the same precedence order as the Rust compiler.
//! Expressions can be grouped using parentheses.
//! The HTML special characters `&`, `<` and `>` will be replaced with their
//! character entities unless the `escape` mode is disabled for a template.
//!
//! # Optional functionality
//!
//! ## Rocket integration
//!
//! Enabling the `with-rocket` feature appends an implementation of Rocket's
//! `Responder` trait for each template type. This makes it easy to trivially
//! return a value of that type in a Rocket handler. See
//! [the example](https://github.com/djc/askama/blob/master/testing/tests/rocket.rs)
//! from the Askama test suite for more on how to integrate.
//!
//! In case a run-time error occurs during templating, a `500 Internal Server
//! Error` `Status` value will be returned, so that this can be further
//! handled by your error catcher.
//!
//! ## Iron integration
//!
//! Enabling the `with-iron` feature appends an implementation of Iron's
//! `Modifier<Response>` trait for each template type. This makes it easy to
//! trivially return a value of that type in an Iron handler. See
//! [the example](https://github.com/djc/askama/blob/master/testing/tests/iron.rs)
//! from the Askama test suite for more on how to integrate.
//!
//! Note that Askama's generated `Modifier<Response>` implementation currently
//! unwraps any run-time errors from the template. If you have a better
//! suggestion, please [file an issue](https://github.com/djc/askama/issues/new).
//!
//! ## The `json` filter
//!
//! Enabling the `serde-json` filter will enable the use of the `json` filter.
//! This will output formatted JSON for any value that implements the required
//! `Serialize` trait.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;
extern crate askama_shared as shared;

use shared::path;

use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut std::fmt::Write) -> Result<()>;
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::new();
        self.render_into(&mut buf)?;
        Ok(buf)
    }
}

pub use shared::filters;
pub use askama_derive::*;
pub use shared::{Error, MarkupDisplay, Result};

#[cfg(feature = "with-iron")]
pub mod iron {
    extern crate iron;
    pub use self::iron::modifier::Modifier;
    pub use self::iron::response::Response;
}

#[cfg(feature = "with-rocket")]
pub mod rocket {
    extern crate rocket;
    pub use self::rocket::http::{ContentType, Status};
    pub use self::rocket::request::Request;
    pub use self::rocket::response::{Responder, Response};
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&path::template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<|endoftext|>