<commit_before>use ammonia;
use iron::prelude::*;
use maud::{DOCTYPE, Markup, PreEscaped, Render};
use pulldown_cmark::{self, Event, Parser, Tag};

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (DOCTYPE)
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            link rel="icon" type="image/png" href=(url_for!(r, "static", "path" => "icon.png")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, ""))
        p {
            "… or view a "
            a href=(url_for!(r, "random")) "random Rustacean"
            "."
        }
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: &str) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search"
                autocomplete="off" value=(value) /
        }
        script (PreEscaped(r#"
            var searchBox = document.getElementById('q')
            if (!searchBox.value) searchBox.select()
        "#))
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, ""))
    })
}

pub fn search_results<'u, I>(
    r: &Request, query: &str, results: I, correction: Option<String>) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, query))
        @if results.peek().is_none() {
            p "No results found."
        } @else if let Some(correction) = correction {
            p {
                "Showing results for "
                a href=(url_for!(r, "search", "q" => &correction[..])) strong (correction)
            }
        }
        @for (user, id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) {
                    (user_title(&id, user.ok()))
                }
            }
            @if let Ok(user) = user {
                (user_box(&id, user, 3))
            }
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    layout(r, Some(&user_title(id, Some(user))), user_box(id, user, 2))
}

fn user_title(id: &str, user: Option<&User>) -> String {
    if let Some(name) = user.and_then(|user| user.name.as_ref()) {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    }
}

fn user_box(id: &str, user: &User, demote_headers: u32) -> Markup {
    html! {
        table {
            tr {
                th "GitHub"
                td a href={ "https://github.com/" (id) } (id)
            }
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown { text: x, demote_headers })
        }
    }
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a> {
    text: &'a str,
    demote_headers: u32,
}

impl<'a> Render for Markdown<'a> {
    fn render(&self) -> Markup {
        let parser = Parser::new_ext(self.text, pulldown_cmark::OPTION_ENABLE_TABLES);
        // Demote headers
        let parser = parser.map(|event| match event {
            Event::Start(Tag::Header(level)) =>
                Event::Start(Tag::Header(level + self.demote_headers as i32)),
            Event::End(Tag::Header(level)) =>
                Event::End(Tag::Header(level + self.demote_headers as i32)),
            _ => event,
        });
        let mut unsafe_html = String::new();
        pulldown_cmark::html::push_html(&mut unsafe_html, parser);
        let safe_html = ammonia::clean(&unsafe_html);
        PreEscaped(safe_html)
    }
}
<commit_msg>Fix Clippy warnings<commit_after>// Allow taking `Markup` by value
#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]

use ammonia;
use iron::prelude::*;
use maud::{DOCTYPE, Markup, PreEscaped, Render};
use pulldown_cmark::{self, Event, Parser, Tag};

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (DOCTYPE)
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            link rel="icon" type="image/png" href=(url_for!(r, "static", "path" => "icon.png")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, ""))
        p {
            "… or view a "
            a href=(url_for!(r, "random")) "random Rustacean"
            "."
        }
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: &str) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search"
                autocomplete="off" value=(value) /
        }
        script (PreEscaped(r#"
            var searchBox = document.getElementById('q')
            if (!searchBox.value) searchBox.select()
        "#))
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, ""))
    })
}

pub fn search_results<'u, I>(
    r: &Request, query: &str, results: I, correction: Option<String>) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, query))
        @if results.peek().is_none() {
            p "No results found."
        } @else if let Some(correction) = correction {
            p {
                "Showing results for "
                a href=(url_for!(r, "search", "q" => &correction[..])) strong (correction)
            }
        }
        @for (user, id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) {
                    (user_title(&id, user.ok()))
                }
            }
            @if let Ok(user) = user {
                (user_box(&id, user, 3))
            }
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    layout(r, Some(&user_title(id, Some(user))), user_box(id, user, 2))
}

fn user_title(id: &str, user: Option<&User>) -> String {
    if let Some(name) = user.and_then(|user| user.name.as_ref()) {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    }
}

fn user_box(id: &str, user: &User, demote_headers: u32) -> Markup {
    html! {
        table {
            tr {
                th "GitHub"
                td a href={ "https://github.com/" (id) } (id)
            }
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown { text: x, demote_headers })
        }
    }
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a> {
    text: &'a str,
    demote_headers: u32,
}

impl<'a> Render for Markdown<'a> {
    fn render(&self) -> Markup {
        let parser = Parser::new_ext(self.text, pulldown_cmark::OPTION_ENABLE_TABLES);
        // Demote headers
        let parser = parser.map(|event| match event {
            Event::Start(Tag::Header(level)) =>
                Event::Start(Tag::Header(level + self.demote_headers as i32)),
            Event::End(Tag::Header(level)) =>
                Event::End(Tag::Header(level + self.demote_headers as i32)),
            _ => event,
        });
        let mut unsafe_html = String::new();
        pulldown_cmark::html::push_html(&mut unsafe_html, parser);
        let safe_html = ammonia::clean(&unsafe_html);
        PreEscaped(safe_html)
    }
}
<|endoftext|>


<commit_before>#![feature(std_misc)]
#![feature(core)]

extern crate para_bm;

use std::time::Duration;
use std::thread::Thread;
use std::num::Float;

use para_bm::{sleep_ns};

fn fast () {
    sleep_ns(1000);
}

fn slow () {
    sleep_ns(10000000);
}

fn my_bench<F> (f: F) -> f64 where F: Fn() {

    // first "throw away" run
    let mut d = Duration::span(|| {
        f();
    });
    let ns = d.num_nanoseconds().unwrap();
    //println!("num nano seconds first run {}", ns);

    let mut sum = 0;
    // iterate to get more cache hits, etc...
    let iters = 100.0;
    for _ in 0 .. iters as usize {
        d = Duration::span(|| {
            f();
        });
        let ns = d.num_nanoseconds().unwrap();
        sum = sum + ns;
    }

    let avg = (sum as f64) / iters;
    //println!("average after first run {}", avg);

    return avg;
}

fn main () {

    let mut max_ns = 10000000.0;
    let mut min_ns = 1.0;

    let num_steps = 100;
    let step_size = (max_ns - min_ns) / num_steps as f64;
    let mut num_ns = min_ns;

    for power in 0 .. num_steps {
        println!("Size.....: {}", num_ns as i64);
        num_ns += step_size;

        let t_avg = my_bench(||{
            let threads_holder = (0 .. 3).map(|_| {
                Thread::scoped(move || {
                    sleep_ns(num_ns as i64);
                })
            }).collect::<Vec<_>>();
        });
        println!("Runtime thread....: {}", t_avg);

        let s_avg = my_bench(||{
            let serial_holder = (0 .. 3).map(|_| {
                sleep_ns(num_ns as i64);
            }).collect::<Vec<_>>();
        });
        println!("Runtime serial....: {}", s_avg);

    }
}
<commit_msg>cutoff size<commit_after>#![feature(std_misc)]
#![feature(core)]

extern crate para_bm;

use std::time::Duration;
use std::thread::Thread;
use std::num::Float;

use para_bm::{sleep_ns};

fn fast () {
    sleep_ns(1000);
}

fn slow () {
    sleep_ns(10000000);
}

fn my_bench<F> (f: F) -> f64 where F: Fn() {

    // first "throw away" run
    let mut d = Duration::span(|| {
        f();
    });
    let ns = d.num_nanoseconds().unwrap();
    //println!("num nano seconds first run {}", ns);

    let mut sum = 0;
    // iterate to get more cache hits, etc...
    let iters = 100.0;
    for _ in 0 .. iters as usize {
        d = Duration::span(|| {
            f();
        });
        let ns = d.num_nanoseconds().unwrap();
        sum = sum + ns;
    }

    let avg = (sum as f64) / iters;
    //println!("average after first run {}", avg);

    return avg;
}

fn main () {

    let mut max_ns = 10000000.0;
    let mut min_ns = 1.0;

    let num_steps = 500;
    let step_size = (max_ns - min_ns) / num_steps as f64;
    let mut num_ns = min_ns;

    for power in 0 .. num_steps {
        println!("Size.....: {}", num_ns as i64);
        num_ns += step_size;

        let t_avg = my_bench(||{
            let threads_holder = (0 .. 3).map(|_| {
                Thread::scoped(move || {
                    sleep_ns(num_ns as i64);
                })
            }).collect::<Vec<_>>();
        });
        println!("Runtime thread....: {}", t_avg);

        let s_avg = my_bench(||{
            let serial_holder = (0 .. 3).map(|_| {
                sleep_ns(num_ns as i64);
            }).collect::<Vec<_>>();
        });
        println!("Runtime serial....: {}", s_avg);

        if t_avg < s_avg {
            println!("Cutoff size {}", num_ns);
            break;
        }
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::collections::HashMap;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use mopa::Any;
use {Index, Generation, Entity, StorageBase, Storage};

/// Abstract component type. Doesn't have to be Copy or even Clone.
pub trait Component: Any + Sized {
    /// Associated storage type for this component.
    type Storage: Storage<Self> + Any + Send + Sync;
}

/// A custom entity iterator. Needed because the world doesn't really store
/// entities directly, but rather has just a vector of Index -> Generation.
pub struct EntityIter<'a> {
    guard: RwLockReadGuard<'a, Vec<Generation>>,
    index: usize,
}

impl<'a> Iterator for EntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        loop {
            match self.guard.get(self.index) {
                Some(&gen) if gen.is_alive() => {
                    let ent = Entity(self.index as Index, gen);
                    self.index += 1;
                    return Some(ent)
                },
                Some(_) => self.index += 1, // continue
                None => return None,
            }
        }
    }
}

/// Helper builder for entities.
pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    /// Adds a `Component` value to the new `Entity`.
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.write::<T>().insert(self.0, value);
        self
    }
    /// Finishes entity construction.
    pub fn build(self) -> Entity {
        self.0
    }
}

struct Appendix {
    next: Entity,
    add_queue: Vec<Entity>,
    sub_queue: Vec<Entity>,
}

fn find_next(gens: &[Generation], lowest_free_index: usize) -> Entity {
    if let Some((id, gen)) = gens.iter().enumerate().skip(lowest_free_index).find(|&(_, g)| !g.is_alive()) {
        return Entity(id as Index, gen.raised());
    }

    let new_index = if lowest_free_index > gens.len() {
        lowest_free_index as Index
    } else {
        gens.len() as Index
    };

    Entity(new_index, Generation(1))
}

/// Entity creation iterator. Will yield new empty entities infinitely.
/// Useful for bulk entity construction, since the locks are only happening once.
pub struct CreateEntityIter<'a> {
    gens: RwLockWriteGuard<'a, Vec<Generation>>,
    app: RwLockWriteGuard<'a, Appendix>,
}

impl<'a> Iterator for CreateEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.app.next;
        assert!(ent.get_gen().is_alive());
        if ent.get_gen().is_first() {
            assert!(self.gens.len() == ent.get_id());
            self.gens.push(ent.get_gen());
            self.app.next.0 += 1;
        } else {
            self.app.next = find_next(&self.gens, ent.get_id() + 1);
        }
        Some(ent)
    }
}

/// A custom entity iterator for dynamically added entities.
pub struct DynamicEntityIter<'a> {
    guard: RwLockReadGuard<'a, Appendix>,
    index: usize,
}

impl<'a> Iterator for DynamicEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.guard.add_queue.get(self.index);
        self.index += 1;
        ent.cloned()
    }
}

trait StorageLock: Any + Send + Sync {
    fn del_slice(&self, &[Entity]);
}

mopafy!(StorageLock);

impl<S: StorageBase + Any + Send + Sync> StorageLock for RwLock<S> {
    fn del_slice(&self, entities: &[Entity]) {
        let mut guard = self.write().unwrap();
        for &e in entities.iter() {
            guard.del(e);
        }
    }
}

/// The `World` struct contains all the data, which is entities and their components.
/// All methods are supposed to be valid for any context they are available in.
pub struct World {
    generations: RwLock<Vec<Generation>>,
    components: HashMap<TypeId, Box<StorageLock>>,
    appendix: RwLock<Appendix>,
}

impl World {
    /// Creates a new empty `World`.
    pub fn new() -> World {
        World {
            generations: RwLock::new(Vec::new()),
            components: HashMap::new(),
            appendix: RwLock::new(Appendix {
                next: Entity(0, Generation(1)),
                add_queue: Vec::new(),
                sub_queue: Vec::new(),
            }),
        }
    }
    /// Registers a new component type.
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    /// Unregisters a component type.
    pub fn unregister<T: Component>(&mut self) -> Option<T::Storage> {
        self.components.remove(&TypeId::of::<T>()).map(|boxed|
            match boxed.downcast::<RwLock<T::Storage>>() {
                Ok(b) => (*b).into_inner().unwrap(),
                Err(_) => panic!("Unable to downcast the storage type"),
            }
        )
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        let boxed = self.components.get(&TypeId::of::<T>())
            .expect("Tried to perform an operation on type that was not registered");
        boxed.downcast_ref().unwrap()
    }
    /// Locks a component's storage for reading.
    pub fn read<T: Component>(&self) -> RwLockReadGuard<T::Storage> {
        self.lock::<T>().read().unwrap()
    }
    /// Locks a component's storage for writing.
    pub fn write<T: Component>(&self) -> RwLockWriteGuard<T::Storage> {
        self.lock::<T>().write().unwrap()
    }
    /// Returns the entity iterator.
    pub fn entities(&self) -> EntityIter {
        EntityIter {
            guard: self.generations.read().unwrap(),
            index: 0,
        }
    }
    /// Returns the dynamic entity iterator. It iterates over entities that were
    /// dynamically created by systems but not yet merged.
    pub fn dynamic_entities(&self) -> DynamicEntityIter {
        DynamicEntityIter {
            guard: self.appendix.read().unwrap(),
            index: 0,
        }
    }
    /// Returns the entity creation iterator. Can be used to create many
    /// empty entities at once without paying the locking overhead.
    pub fn create_iter(&self) -> CreateEntityIter {
        CreateEntityIter {
            gens: self.generations.write().unwrap(),
            app: self.appendix.write().unwrap(),
        }
    }
    /// Creates a new entity instantly, locking the generations data.
    pub fn create_now(&self) -> EntityBuilder {
        let mut gens = self.generations.write().unwrap();
        let mut app = self.appendix.write().unwrap();
        let ent = app.next;
        assert!(ent.get_gen().is_alive());
        if ent.get_gen().is_first() {
            assert!(gens.len() == ent.get_id());
            gens.push(ent.get_gen());
            app.next.0 += 1;
        } else {
            assert!(!gens[ent.get_id()].is_alive());
            gens[ent.get_id()] = ent.get_gen();
            app.next = find_next(&gens, ent.get_id() + 1);
        }
        EntityBuilder(ent, self)
    }
    /// Deletes a new entity instantly, locking the generations data.
    pub fn delete_now(&self, entity: Entity) {
        for comp in self.components.values() {
            comp.del_slice(&[entity]);
        }
        let mut gens = self.generations.write().unwrap();
        let mut gen = &mut gens[entity.get_id()];
        gen.die();
        let mut app = self.appendix.write().unwrap();
        if entity.get_id() < app.next.get_id() {
            app.next = Entity(entity.0, gen.raised());
        }
    }
    /// Creates a new entity dynamically.
    pub fn create_later(&self) -> Entity {
        let gens = self.generations.read().unwrap();
        let mut app = self.appendix.write().unwrap();
        let ent = app.next;
        app.add_queue.push(ent);
        app.next = find_next(&gens, ent.get_id() + 1);
        ent
    }
    /// Deletes an entity dynamically.
    pub fn delete_later(&self, entity: Entity) {
        let mut app = self.appendix.write().unwrap();
        app.sub_queue.push(entity);
    }
    /// Returns `true` if the given `Entity` is alive.
    pub fn is_alive(&self, entity: Entity) -> bool {
        debug_assert!(entity.get_gen().is_alive());
        let gens = self.generations.read().unwrap();
        entity.get_gen() == gens[entity.get_id()]
    }
    /// Merges in the appendix, recording all the dynamically created
    /// and deleted entities into the persistent generations vector.
    /// Also removes all the abandoned components.
    pub fn merge(&self) {
        // We can't lock Appendix and components at the same time,
        // or otherwise we deadlock with a system that tries to process
        // newly added entities.
        // So we copy dead components out first, and then process them separately.
        let mut temp_list = Vec::new(); //TODO: avoid allocation
        {
            let mut gens = self.generations.write().unwrap();
            let mut app = self.appendix.write().unwrap();
            for ent in app.add_queue.drain(..) {
                while gens.len() <= ent.get_id() {
                    gens.push(Generation(0));
                }
                assert_eq!(ent.get_gen(), gens[ent.get_id()].raised());
                gens[ent.get_id()] = ent.get_gen();
            }
            let mut next = app.next;
            for ent in app.sub_queue.drain(..) {
                let gen = &mut gens[ent.get_id()];
                if gen.is_alive() {
                    assert_eq!(ent.get_gen(), *gen);
                    gen.die();
                    temp_list.push(ent);
                    if ent.get_id() < next.get_id() {
                        next = Entity(ent.0, gen.raised());
                    }
                } else {
                    let mut g = ent.get_gen();
                    g.die();
                    debug_assert_eq!(g, *gen);
                }
            }
            app.next = next;
        }
        for comp in self.components.values() {
            comp.del_slice(&temp_list);
        }
    }
}

/// System fetch-time argument. The fetch is executed at the start of the run.
/// It contains a subset of `World` methods that make sense during initialization.
pub struct FetchArg<'a>(&'a World);

impl<'a> FetchArg<'a> {
    /// Constructs a new `FetchArg`, not supposed to be used.
    #[doc(hidden)]
    pub fn new(w: &'a World) -> FetchArg<'a> {
        FetchArg(w)
    }
    /// Locks a `Component` for reading.
    pub fn read<T: Component>(&self) -> RwLockReadGuard<'a, T::Storage> {
        self.0.read::<T>()
    }
    /// Locks a `Component` for writing.
    pub fn write<T: Component>(&self) -> RwLockWriteGuard<'a, T::Storage> {
        self.0.write::<T>()
    }
    /// Returns the entity iterator.
    pub fn entities(self) -> EntityIter<'a> {
        self.0.entities()
    }
}
<commit_msg>replace two asserts with assert_eq!s<commit_after>use std::any::TypeId;
use std::collections::HashMap;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use mopa::Any;
use {Index, Generation, Entity, StorageBase, Storage};

/// Abstract component type. Doesn't have to be Copy or even Clone.
pub trait Component: Any + Sized {
    /// Associated storage type for this component.
    type Storage: Storage<Self> + Any + Send + Sync;
}

/// A custom entity iterator. Needed because the world doesn't really store
/// entities directly, but rather has just a vector of Index -> Generation.
pub struct EntityIter<'a> {
    guard: RwLockReadGuard<'a, Vec<Generation>>,
    index: usize,
}

impl<'a> Iterator for EntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        loop {
            match self.guard.get(self.index) {
                Some(&gen) if gen.is_alive() => {
                    let ent = Entity(self.index as Index, gen);
                    self.index += 1;
                    return Some(ent)
                },
                Some(_) => self.index += 1, // continue
                None => return None,
            }
        }
    }
}

/// Helper builder for entities.
pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    /// Adds a `Component` value to the new `Entity`.
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.write::<T>().insert(self.0, value);
        self
    }
    /// Finishes entity construction.
    pub fn build(self) -> Entity {
        self.0
    }
}

struct Appendix {
    next: Entity,
    add_queue: Vec<Entity>,
    sub_queue: Vec<Entity>,
}

fn find_next(gens: &[Generation], lowest_free_index: usize) -> Entity {
    if let Some((id, gen)) = gens.iter().enumerate().skip(lowest_free_index).find(|&(_, g)| !g.is_alive()) {
        return Entity(id as Index, gen.raised());
    }

    let new_index = if lowest_free_index > gens.len() {
        lowest_free_index as Index
    } else {
        gens.len() as Index
    };

    Entity(new_index, Generation(1))
}

/// Entity creation iterator. Will yield new empty entities infinitely.
/// Useful for bulk entity construction, since the locks are only happening once.
pub struct CreateEntityIter<'a> {
    gens: RwLockWriteGuard<'a, Vec<Generation>>,
    app: RwLockWriteGuard<'a, Appendix>,
}

impl<'a> Iterator for CreateEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.app.next;
        assert!(ent.get_gen().is_alive());
        if ent.get_gen().is_first() {
            assert_eq!(self.gens.len(), ent.get_id());
            self.gens.push(ent.get_gen());
            self.app.next.0 += 1;
        } else {
            self.app.next = find_next(&self.gens, ent.get_id() + 1);
        }
        Some(ent)
    }
}

/// A custom entity iterator for dynamically added entities.
pub struct DynamicEntityIter<'a> {
    guard: RwLockReadGuard<'a, Appendix>,
    index: usize,
}

impl<'a> Iterator for DynamicEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.guard.add_queue.get(self.index);
        self.index += 1;
        ent.cloned()
    }
}

trait StorageLock: Any + Send + Sync {
    fn del_slice(&self, &[Entity]);
}

mopafy!(StorageLock);

impl<S: StorageBase + Any + Send + Sync> StorageLock for RwLock<S> {
    fn del_slice(&self, entities: &[Entity]) {
        let mut guard = self.write().unwrap();
        for &e in entities.iter() {
            guard.del(e);
        }
    }
}

/// The `World` struct contains all the data, which is entities and their components.
/// All methods are supposed to be valid for any context they are available in.
pub struct World {
    generations: RwLock<Vec<Generation>>,
    components: HashMap<TypeId, Box<StorageLock>>,
    appendix: RwLock<Appendix>,
}

impl World {
    /// Creates a new empty `World`.
    pub fn new() -> World {
        World {
            generations: RwLock::new(Vec::new()),
            components: HashMap::new(),
            appendix: RwLock::new(Appendix {
                next: Entity(0, Generation(1)),
                add_queue: Vec::new(),
                sub_queue: Vec::new(),
            }),
        }
    }
    /// Registers a new component type.
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    /// Unregisters a component type.
    pub fn unregister<T: Component>(&mut self) -> Option<T::Storage> {
        self.components.remove(&TypeId::of::<T>()).map(|boxed|
            match boxed.downcast::<RwLock<T::Storage>>() {
                Ok(b) => (*b).into_inner().unwrap(),
                Err(_) => panic!("Unable to downcast the storage type"),
            }
        )
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        let boxed = self.components.get(&TypeId::of::<T>())
            .expect("Tried to perform an operation on type that was not registered");
        boxed.downcast_ref().unwrap()
    }
    /// Locks a component's storage for reading.
    pub fn read<T: Component>(&self) -> RwLockReadGuard<T::Storage> {
        self.lock::<T>().read().unwrap()
    }
    /// Locks a component's storage for writing.
    pub fn write<T: Component>(&self) -> RwLockWriteGuard<T::Storage> {
        self.lock::<T>().write().unwrap()
    }
    /// Returns the entity iterator.
    pub fn entities(&self) -> EntityIter {
        EntityIter {
            guard: self.generations.read().unwrap(),
            index: 0,
        }
    }
    /// Returns the dynamic entity iterator. It iterates over entities that were
    /// dynamically created by systems but not yet merged.
    pub fn dynamic_entities(&self) -> DynamicEntityIter {
        DynamicEntityIter {
            guard: self.appendix.read().unwrap(),
            index: 0,
        }
    }
    /// Returns the entity creation iterator. Can be used to create many
    /// empty entities at once without paying the locking overhead.
    pub fn create_iter(&self) -> CreateEntityIter {
        CreateEntityIter {
            gens: self.generations.write().unwrap(),
            app: self.appendix.write().unwrap(),
        }
    }
    /// Creates a new entity instantly, locking the generations data.
    pub fn create_now(&self) -> EntityBuilder {
        let mut gens = self.generations.write().unwrap();
        let mut app = self.appendix.write().unwrap();
        let ent = app.next;
        assert!(ent.get_gen().is_alive());
        if ent.get_gen().is_first() {
            assert_eq!(gens.len(), ent.get_id());
            gens.push(ent.get_gen());
            app.next.0 += 1;
        } else {
            assert!(!gens[ent.get_id()].is_alive());
            gens[ent.get_id()] = ent.get_gen();
            app.next = find_next(&gens, ent.get_id() + 1);
        }
        EntityBuilder(ent, self)
    }
    /// Deletes a new entity instantly, locking the generations data.
    pub fn delete_now(&self, entity: Entity) {
        for comp in self.components.values() {
            comp.del_slice(&[entity]);
        }
        let mut gens = self.generations.write().unwrap();
        let mut gen = &mut gens[entity.get_id()];
        gen.die();
        let mut app = self.appendix.write().unwrap();
        if entity.get_id() < app.next.get_id() {
            app.next = Entity(entity.0, gen.raised());
        }
    }
    /// Creates a new entity dynamically.
    pub fn create_later(&self) -> Entity {
        let gens = self.generations.read().unwrap();
        let mut app = self.appendix.write().unwrap();
        let ent = app.next;
        app.add_queue.push(ent);
        app.next = find_next(&gens, ent.get_id() + 1);
        ent
    }
    /// Deletes an entity dynamically.
    pub fn delete_later(&self, entity: Entity) {
        let mut app = self.appendix.write().unwrap();
        app.sub_queue.push(entity);
    }
    /// Returns `true` if the given `Entity` is alive.
    pub fn is_alive(&self, entity: Entity) -> bool {
        debug_assert!(entity.get_gen().is_alive());
        let gens = self.generations.read().unwrap();
        entity.get_gen() == gens[entity.get_id()]
    }
    /// Merges in the appendix, recording all the dynamically created
    /// and deleted entities into the persistent generations vector.
    /// Also removes all the abandoned components.
    pub fn merge(&self) {
        // We can't lock Appendix and components at the same time,
        // or otherwise we deadlock with a system that tries to process
        // newly added entities.
        // So we copy dead components out first, and then process them separately.
        let mut temp_list = Vec::new(); //TODO: avoid allocation
        {
            let mut gens = self.generations.write().unwrap();
            let mut app = self.appendix.write().unwrap();
            for ent in app.add_queue.drain(..) {
                while gens.len() <= ent.get_id() {
                    gens.push(Generation(0));
                }
                assert_eq!(ent.get_gen(), gens[ent.get_id()].raised());
                gens[ent.get_id()] = ent.get_gen();
            }
            let mut next = app.next;
            for ent in app.sub_queue.drain(..) {
                let gen = &mut gens[ent.get_id()];
                if gen.is_alive() {
                    assert_eq!(ent.get_gen(), *gen);
                    gen.die();
                    temp_list.push(ent);
                    if ent.get_id() < next.get_id() {
                        next = Entity(ent.0, gen.raised());
                    }
                } else {
                    let mut g = ent.get_gen();
                    g.die();
                    debug_assert_eq!(g, *gen);
                }
            }
            app.next = next;
        }
        for comp in self.components.values() {
            comp.del_slice(&temp_list);
        }
    }
}

/// System fetch-time argument. The fetch is executed at the start of the run.
/// It contains a subset of `World` methods that make sense during initialization.
pub struct FetchArg<'a>(&'a World);

impl<'a> FetchArg<'a> {
    /// Constructs a new `FetchArg`, not supposed to be used.
    #[doc(hidden)]
    pub fn new(w: &'a World) -> FetchArg<'a> {
        FetchArg(w)
    }
    /// Locks a `Component` for reading.
    pub fn read<T: Component>(&self) -> RwLockReadGuard<'a, T::Storage> {
        self.0.read::<T>()
    }
    /// Locks a `Component` for writing.
    pub fn write<T: Component>(&self) -> RwLockWriteGuard<'a, T::Storage> {
        self.0.write::<T>()
    }
    /// Returns the entity iterator.
    pub fn entities(self) -> EntityIter<'a> {
        self.0.entities()
    }
}
<|endoftext|>


<commit_before>use ide_db::assists::GroupLabel;
use itertools::Itertools;
use stdx::to_lower_snake_case;
use syntax::ast::HasVisibility;
use syntax::ast::{self, AstNode, HasName};

use crate::{
    utils::{add_method_to_adt, find_struct_impl},
    AssistContext, AssistId, AssistKind, Assists,
};

// Assist: generate_enum_try_into_method
//
// Generate a `try_into_` method for this enum variant.
//
// ```
// enum Value {
//  Number(i32),
//  Text(String)$0,
// }
// ```
// ->
// ```
// enum Value {
//  Number(i32),
//  Text(String),
// }
//
// impl Value {
//     fn try_into_text(self) -> Result<String, Self> {
//         if let Self::Text(v) = self {
//             Ok(v)
//         } else {
//             Err(self)
//         }
//     }
// }
// ```
pub(crate) fn generate_enum_try_into_method(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
) -> Option<()> {
    generate_enum_projection_method(
        acc,
        ctx,
        "generate_enum_try_into_method",
        "Generate a `try_into_` method for this enum variant",
        ProjectionProps {
            fn_name_prefix: "try_into",
            self_param: "self",
            return_prefix: "Result<",
            return_suffix: ", Self>",
            happy_case: "Ok",
            sad_case: "Err(self)",
        },
    )
}

// Assist: generate_enum_as_method
//
// Generate an `as_` method for this enum variant.
//
// ```
// enum Value {
//  Number(i32),
//  Text(String)$0,
// }
// ```
// ->
// ```
// enum Value {
//  Number(i32),
//  Text(String),
// }
//
// impl Value {
//     fn as_text(&self) -> Option<&String> {
//         if let Self::Text(v) = self {
//             Some(v)
//         } else {
//             None
//         }
//     }
// }
// ```
pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    generate_enum_projection_method(
        acc,
        ctx,
        "generate_enum_as_method",
        "Generate an `as_` method for this enum variant",
        ProjectionProps {
            fn_name_prefix: "as",
            self_param: "&self",
            return_prefix: "Option<&",
            return_suffix: ">",
            happy_case: "Some",
            sad_case: "None",
        },
    )
}

struct ProjectionProps {
    fn_name_prefix: &'static str,
    self_param: &'static str,
    return_prefix: &'static str,
    return_suffix: &'static str,
    happy_case: &'static str,
    sad_case: &'static str,
}

fn generate_enum_projection_method(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    assist_id: &'static str,
    assist_description: &str,
    props: ProjectionProps,
) -> Option<()> {
    let ProjectionProps {
        fn_name_prefix,
        self_param,
        return_prefix,
        return_suffix,
        happy_case,
        sad_case,
    } = props;

    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
    let variant_name = variant.name()?;
    let parent_enum = ast::Adt::Enum(variant.parent_enum());

    let (pattern_suffix, field_type, bound_name) = match variant.kind() {
        ast::StructKind::Record(record) => {
            let (field,) = record.fields().collect_tuple()?;
            let name = field.name()?.to_string();
            let ty = field.ty()?;
            let pattern_suffix = format!(" {{ {name} }}");
            (pattern_suffix, ty, name)
        }
        ast::StructKind::Tuple(tuple) => {
            let (field,) = tuple.fields().collect_tuple()?;
            let ty = field.ty()?;
            ("(v)".to_owned(), ty, "v".to_owned())
        }
        ast::StructKind::Unit => return None,
    };

    let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text()));

    // Return early if we've found an existing new fn
    let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;

    let target = variant.syntax().text_range();
    acc.add_group(
        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
        AssistId(assist_id, AssistKind::Generate),
        assist_description,
        target,
        |builder| {
            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));

            let field_type_syntax = field_type.syntax();

            let must_use = if ctx.config.assist_emit_must_use {
                "#[must_use]\n"
            } else {
                ""
            };

            let method = format!(
                "    {must_use}{vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type_syntax}{return_suffix} {{
        if let Self::{variant_name}{pattern_suffix} = self {{
            {happy_case}({bound_name})
        }} else {{
            {sad_case}
        }}
    }}"
            );

            add_method_to_adt(builder, &parent_enum, impl_def, &method);
        },
    )
}

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

    use super::*;

    #[test]
    fn test_generate_enum_try_into_tuple_variant() {
        check_assist(
            generate_enum_try_into_method,
            r#"
enum Value {
    Number(i32),
    Text(String)$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text(String),
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text(v) = self {
            Ok(v)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_already_implemented() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String)$0,
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text(v) = self {
            Ok(v)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_unit_variant() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String),
    Unit$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_record_with_multiple_fields() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String),
    Both { first: i32, second: String }$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_tuple_with_multiple_fields() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String, String)$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_record_variant() {
        check_assist(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text { text: String }$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text { text: String },
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text { text } = self {
            Ok(text)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_as_tuple_variant() {
        check_assist(
            generate_enum_as_method,
            r#"
enum Value {
    Number(i32),
    Text(String)$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text(String),
}

impl Value {
    fn as_text(&self) -> Option<&String> {
        if let Self::Text(v) = self {
            Some(v)
        } else {
            None
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_as_record_variant() {
        check_assist(
            generate_enum_as_method,
            r#"enum Value {
    Number(i32),
    Text { text: String }$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text { text: String },
}

impl Value {
    fn as_text(&self) -> Option<&String> {
        if let Self::Text { text } = self {
            Some(text)
        } else {
            None
        }
    }
}"#,
        );
    }
}
<commit_msg>fix: indentation after inserting `#must_use`<commit_after>use ide_db::assists::GroupLabel;
use itertools::Itertools;
use stdx::to_lower_snake_case;
use syntax::ast::HasVisibility;
use syntax::ast::{self, AstNode, HasName};

use crate::{
    utils::{add_method_to_adt, find_struct_impl},
    AssistContext, AssistId, AssistKind, Assists,
};

// Assist: generate_enum_try_into_method
//
// Generate a `try_into_` method for this enum variant.
//
// ```
// enum Value {
//  Number(i32),
//  Text(String)$0,
// }
// ```
// ->
// ```
// enum Value {
//  Number(i32),
//  Text(String),
// }
//
// impl Value {
//     fn try_into_text(self) -> Result<String, Self> {
//         if let Self::Text(v) = self {
//             Ok(v)
//         } else {
//             Err(self)
//         }
//     }
// }
// ```
pub(crate) fn generate_enum_try_into_method(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
) -> Option<()> {
    generate_enum_projection_method(
        acc,
        ctx,
        "generate_enum_try_into_method",
        "Generate a `try_into_` method for this enum variant",
        ProjectionProps {
            fn_name_prefix: "try_into",
            self_param: "self",
            return_prefix: "Result<",
            return_suffix: ", Self>",
            happy_case: "Ok",
            sad_case: "Err(self)",
        },
    )
}

// Assist: generate_enum_as_method
//
// Generate an `as_` method for this enum variant.
//
// ```
// enum Value {
//  Number(i32),
//  Text(String)$0,
// }
// ```
// ->
// ```
// enum Value {
//  Number(i32),
//  Text(String),
// }
//
// impl Value {
//     fn as_text(&self) -> Option<&String> {
//         if let Self::Text(v) = self {
//             Some(v)
//         } else {
//             None
//         }
//     }
// }
// ```
pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    generate_enum_projection_method(
        acc,
        ctx,
        "generate_enum_as_method",
        "Generate an `as_` method for this enum variant",
        ProjectionProps {
            fn_name_prefix: "as",
            self_param: "&self",
            return_prefix: "Option<&",
            return_suffix: ">",
            happy_case: "Some",
            sad_case: "None",
        },
    )
}

struct ProjectionProps {
    fn_name_prefix: &'static str,
    self_param: &'static str,
    return_prefix: &'static str,
    return_suffix: &'static str,
    happy_case: &'static str,
    sad_case: &'static str,
}

fn generate_enum_projection_method(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    assist_id: &'static str,
    assist_description: &str,
    props: ProjectionProps,
) -> Option<()> {
    let ProjectionProps {
        fn_name_prefix,
        self_param,
        return_prefix,
        return_suffix,
        happy_case,
        sad_case,
    } = props;

    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
    let variant_name = variant.name()?;
    let parent_enum = ast::Adt::Enum(variant.parent_enum());

    let (pattern_suffix, field_type, bound_name) = match variant.kind() {
        ast::StructKind::Record(record) => {
            let (field,) = record.fields().collect_tuple()?;
            let name = field.name()?.to_string();
            let ty = field.ty()?;
            let pattern_suffix = format!(" {{ {name} }}");
            (pattern_suffix, ty, name)
        }
        ast::StructKind::Tuple(tuple) => {
            let (field,) = tuple.fields().collect_tuple()?;
            let ty = field.ty()?;
            ("(v)".to_owned(), ty, "v".to_owned())
        }
        ast::StructKind::Unit => return None,
    };

    let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text()));

    // Return early if we've found an existing new fn
    let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;

    let target = variant.syntax().text_range();
    acc.add_group(
        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
        AssistId(assist_id, AssistKind::Generate),
        assist_description,
        target,
        |builder| {
            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));

            let field_type_syntax = field_type.syntax();

            let must_use = if ctx.config.assist_emit_must_use {
                "#[must_use]\n    "
            } else {
                ""
            };

            let method = format!(
                "    {must_use}{vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type_syntax}{return_suffix} {{
        if let Self::{variant_name}{pattern_suffix} = self {{
            {happy_case}({bound_name})
        }} else {{
            {sad_case}
        }}
    }}"
            );

            add_method_to_adt(builder, &parent_enum, impl_def, &method);
        },
    )
}

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

    use super::*;

    #[test]
    fn test_generate_enum_try_into_tuple_variant() {
        check_assist(
            generate_enum_try_into_method,
            r#"
enum Value {
    Number(i32),
    Text(String)$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text(String),
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text(v) = self {
            Ok(v)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_already_implemented() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String)$0,
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text(v) = self {
            Ok(v)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_unit_variant() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String),
    Unit$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_record_with_multiple_fields() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String),
    Both { first: i32, second: String }$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_tuple_with_multiple_fields() {
        check_assist_not_applicable(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text(String, String)$0,
}"#,
        );
    }

    #[test]
    fn test_generate_enum_try_into_record_variant() {
        check_assist(
            generate_enum_try_into_method,
            r#"enum Value {
    Number(i32),
    Text { text: String }$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text { text: String },
}

impl Value {
    fn try_into_text(self) -> Result<String, Self> {
        if let Self::Text { text } = self {
            Ok(text)
        } else {
            Err(self)
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_as_tuple_variant() {
        check_assist(
            generate_enum_as_method,
            r#"
enum Value {
    Number(i32),
    Text(String)$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text(String),
}

impl Value {
    fn as_text(&self) -> Option<&String> {
        if let Self::Text(v) = self {
            Some(v)
        } else {
            None
        }
    }
}"#,
        );
    }

    #[test]
    fn test_generate_enum_as_record_variant() {
        check_assist(
            generate_enum_as_method,
            r#"enum Value {
    Number(i32),
    Text { text: String }$0,
}"#,
            r#"enum Value {
    Number(i32),
    Text { text: String },
}

impl Value {
    fn as_text(&self) -> Option<&String> {
        if let Self::Text { text } = self {
            Some(text)
        } else {
            None
        }
    }
}"#,
        );
    }
}
<|endoftext|>


<commit_before>use hir::AsAssocItem;
use ide_db::helpers::{
    insert_use::{insert_use, ImportScope},
    mod_path_to_ast,
};
use syntax::{
    ast::{self, make},
    match_ast, ted, AstNode, SyntaxNode,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_qualified_name_with_use
//
// Adds a use statement for a given fully-qualified name.
//
// ```
// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
// fn process(map: std::collections::$0HashMap<String, String>) {}
// ```
// ->
// ```
// use std::collections::HashMap;
//
// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
// fn process(map: HashMap<String, String>) {}
// ```
pub(crate) fn replace_qualified_name_with_use(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let path: ast::Path = ctx.find_node_at_offset()?;
    // We don't want to mess with use statements
    if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
        cov_mark::hit!(not_applicable_in_use);
        return None;
    }

    if path.qualifier().is_none() {
        cov_mark::hit!(dont_import_trivial_paths);
        return None;
    }

    // only offer replacement for non assoc items
    match ctx.sema.resolve_path(&path)? {
        hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
        hir::PathResolution::Macro(_) => (),
        _ => return None,
    }
    // then search for an import for the first path segment of what we want to replace
    // that way it is less likely that we import the item from a different location due re-exports
    let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? {
        hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
        _ => return None,
    };

    let starts_with_name_ref = !matches!(
        path.first_segment().and_then(|it| it.kind()),
        Some(
            ast::PathSegmentKind::CrateKw
                | ast::PathSegmentKind::SuperKw
                | ast::PathSegmentKind::SelfKw
        )
    );
    let path_to_qualifier = starts_with_name_ref
        .then(|| {
            ctx.sema.scope(path.syntax()).module().and_then(|m| {
                m.find_use_path_prefixed(ctx.sema.db, module, ctx.config.insert_use.prefix_kind)
            })
        })
        .flatten();

    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
    let target = path.syntax().text_range();
    acc.add(
        AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
        "Replace qualified path with use",
        target,
        |builder| {
            // Now that we've brought the name into scope, re-qualify all paths that could be
            // affected (that is, all paths inside the node we added the `use` to).
            let scope = match scope {
                ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
                ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
                ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
            };
            shorten_paths(scope.as_syntax_node(), &path.clone_for_update());
            // stick the found import in front of the to be replaced path
            let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) {
                Some(qualifier) => make::path_concat(qualifier, path),
                None => path,
            };
            insert_use(&scope, path, &ctx.config.insert_use);
        },
    )
}

/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
fn shorten_paths(node: &SyntaxNode, path: &ast::Path) {
    for child in node.children() {
        match_ast! {
            match child {
                // Don't modify `use` items, as this can break the `use` item when injecting a new
                // import into the use tree.
                ast::Use(_) => continue,
                // Don't descend into submodules, they don't have the same `use` items in scope.
                // FIXME: This isn't true due to `super::*` imports?
                ast::Module(_) => continue,
                ast::Path(p) => if maybe_replace_path(p.clone(), path.clone()).is_none() {
                    shorten_paths(p.syntax(), path);
                },
                _ => shorten_paths(&child, path),
            }
        }
    }
}

fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
    if !path_eq_no_generics(path.clone(), target) {
        return None;
    }

    // Shorten `path`, leaving only its last segment.
    if let Some(parent) = path.qualifier() {
        ted::remove(parent.syntax());
    }
    if let Some(double_colon) = path.coloncolon_token() {
        ted::remove(&double_colon);
    }

    Some(())
}

fn path_eq_no_generics(lhs: ast::Path, rhs: ast::Path) -> bool {
    let mut lhs_curr = lhs;
    let mut rhs_curr = rhs;
    loop {
        match lhs_curr.segment().zip(rhs_curr.segment()) {
            Some((lhs, rhs))
                if lhs.coloncolon_token().is_some() == rhs.coloncolon_token().is_some()
                    && lhs
                        .name_ref()
                        .zip(rhs.name_ref())
                        .map_or(false, |(lhs, rhs)| lhs.text() == rhs.text()) => {}
            _ => return false,
        }

        match (lhs_curr.qualifier(), rhs_curr.qualifier()) {
            (Some(lhs), Some(rhs)) => {
                lhs_curr = lhs;
                rhs_curr = rhs;
            }
            (None, None) => return true,
            _ => return false,
        }
    }
}

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

    use super::*;

    #[test]
    fn test_replace_already_imported() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
use std::fs;

fn main() {
    std::f$0s::Path
}",
            r"
mod std { pub mod fs { pub struct Path; } }
use std::fs;

fn main() {
    fs::Path
}",
        )
    }

    #[test]
    fn test_replace_add_use_no_anchor() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
std::fs::Path$0
    ",
            r"
use std::fs::Path;

mod std { pub mod fs { pub struct Path; } }
Path
    ",
        );
    }

    #[test]
    fn test_replace_add_use_no_anchor_middle_segment() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
std::fs$0::Path
    ",
            r"
use std::fs;

mod std { pub mod fs { pub struct Path; } }
fs::Path
    ",
        );
    }

    #[test]
    fn dont_import_trivial_paths() {
        cov_mark::check!(dont_import_trivial_paths);
        check_assist_not_applicable(replace_qualified_name_with_use, r"impl foo$0 for () {}");
    }

    #[test]
    fn test_replace_not_applicable_in_use() {
        cov_mark::check!(not_applicable_in_use);
        check_assist_not_applicable(replace_qualified_name_with_use, r"use std::fmt$0;");
    }

    #[test]
    fn replaces_all_affected_paths() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    std::fmt::Debug$0;
    let x: std::fmt::Debug = std::fmt::Debug;
}
    ",
            r"
use std::fmt::Debug;

mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    Debug;
    let x: Debug = Debug;
}
    ",
        );
    }

    #[test]
    fn does_not_replace_in_submodules() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    std::fmt::Debug$0;
}

mod sub {
    fn f() {
        std::fmt::Debug;
    }
}
    ",
            r"
use std::fmt::Debug;

mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    Debug;
}

mod sub {
    fn f() {
        std::fmt::Debug;
    }
}
    ",
        );
    }

    #[test]
    fn does_not_replace_in_use() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Display {} } }
use std::fmt::Display;

fn main() {
    std::fmt$0;
}
    ",
            r"
mod std { pub mod fmt { pub trait Display {} } }
use std::fmt::{Display, self};

fn main() {
    fmt;
}
    ",
        );
    }

    #[test]
    fn does_not_replace_assoc_item_path() {
        check_assist_not_applicable(
            replace_qualified_name_with_use,
            r"
pub struct Foo;
impl Foo {
    pub fn foo() {}
}

fn main() {
    Foo::foo$0();
}
",
        );
    }

    #[test]
    fn replace_reuses_path_qualifier() {
        check_assist(
            replace_qualified_name_with_use,
            r"
pub mod foo {
    pub struct Foo;
}

mod bar {
    pub use super::foo::Foo as Bar;
}

fn main() {
    foo::Foo$0;
}
",
            r"
use foo::Foo;

pub mod foo {
    pub struct Foo;
}

mod bar {
    pub use super::foo::Foo as Bar;
}

fn main() {
    Foo;
}
",
        );
    }

    #[test]
    fn replace_does_not_always_try_to_replace_by_full_item_path() {
        check_assist(
            replace_qualified_name_with_use,
            r"
use std::mem;

mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    mem::drop$0(0);
}
",
            r"
use std::mem::{self, drop};

mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    drop(0);
}
",
        );
    }
}
<commit_msg>Drop generic args in path before insert use<commit_after>use hir::AsAssocItem;
use ide_db::helpers::{
    insert_use::{insert_use, ImportScope},
    mod_path_to_ast,
};
use syntax::{
    ast::{self, make},
    match_ast, ted, AstNode, SyntaxNode,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_qualified_name_with_use
//
// Adds a use statement for a given fully-qualified name.
//
// ```
// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
// fn process(map: std::collections::$0HashMap<String, String>) {}
// ```
// ->
// ```
// use std::collections::HashMap;
//
// # mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
// fn process(map: HashMap<String, String>) {}
// ```
pub(crate) fn replace_qualified_name_with_use(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let path: ast::Path = ctx.find_node_at_offset()?;
    // We don't want to mess with use statements
    if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
        cov_mark::hit!(not_applicable_in_use);
        return None;
    }

    if path.qualifier().is_none() {
        cov_mark::hit!(dont_import_trivial_paths);
        return None;
    }

    // only offer replacement for non assoc items
    match ctx.sema.resolve_path(&path)? {
        hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
        hir::PathResolution::Macro(_) => (),
        _ => return None,
    }
    // then search for an import for the first path segment of what we want to replace
    // that way it is less likely that we import the item from a different location due re-exports
    let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? {
        hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
        _ => return None,
    };

    let starts_with_name_ref = !matches!(
        path.first_segment().and_then(|it| it.kind()),
        Some(
            ast::PathSegmentKind::CrateKw
                | ast::PathSegmentKind::SuperKw
                | ast::PathSegmentKind::SelfKw
        )
    );
    let path_to_qualifier = starts_with_name_ref
        .then(|| {
            ctx.sema.scope(path.syntax()).module().and_then(|m| {
                m.find_use_path_prefixed(ctx.sema.db, module, ctx.config.insert_use.prefix_kind)
            })
        })
        .flatten();

    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
    let target = path.syntax().text_range();
    acc.add(
        AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
        "Replace qualified path with use",
        target,
        |builder| {
            // Now that we've brought the name into scope, re-qualify all paths that could be
            // affected (that is, all paths inside the node we added the `use` to).
            let scope = match scope {
                ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
                ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
                ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
            };
            shorten_paths(scope.as_syntax_node(), &path);
            let path = drop_generic_args(&path);
            // stick the found import in front of the to be replaced path
            let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) {
                Some(qualifier) => make::path_concat(qualifier, path),
                None => path,
            };
            insert_use(&scope, path, &ctx.config.insert_use);
        },
    )
}

fn drop_generic_args(path: &ast::Path) -> ast::Path {
    let path = path.clone_for_update();
    if let Some(segment) = path.segment() {
        if let Some(generic_args) = segment.generic_arg_list() {
            ted::remove(generic_args.syntax());
        }
    }
    path
}

/// Mutates `node` to shorten `path` in all descendants of `node`.
fn shorten_paths(node: &SyntaxNode, path: &ast::Path) {
    for child in node.children() {
        match_ast! {
            match child {
                // Don't modify `use` items, as this can break the `use` item when injecting a new
                // import into the use tree.
                ast::Use(_) => continue,
                // Don't descend into submodules, they don't have the same `use` items in scope.
                // FIXME: This isn't true due to `super::*` imports?
                ast::Module(_) => continue,
                ast::Path(p) => if maybe_replace_path(p.clone(), path.clone()).is_none() {
                    shorten_paths(p.syntax(), path);
                },
                _ => shorten_paths(&child, path),
            }
        }
    }
}

fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
    if !path_eq_no_generics(path.clone(), target) {
        return None;
    }

    // Shorten `path`, leaving only its last segment.
    if let Some(parent) = path.qualifier() {
        ted::remove(parent.syntax());
    }
    if let Some(double_colon) = path.coloncolon_token() {
        ted::remove(&double_colon);
    }

    Some(())
}

fn path_eq_no_generics(lhs: ast::Path, rhs: ast::Path) -> bool {
    let mut lhs_curr = lhs;
    let mut rhs_curr = rhs;
    loop {
        match lhs_curr.segment().zip(rhs_curr.segment()) {
            Some((lhs, rhs))
                if lhs.coloncolon_token().is_some() == rhs.coloncolon_token().is_some()
                    && lhs
                        .name_ref()
                        .zip(rhs.name_ref())
                        .map_or(false, |(lhs, rhs)| lhs.text() == rhs.text()) => {}
            _ => return false,
        }

        match (lhs_curr.qualifier(), rhs_curr.qualifier()) {
            (Some(lhs), Some(rhs)) => {
                lhs_curr = lhs;
                rhs_curr = rhs;
            }
            (None, None) => return true,
            _ => return false,
        }
    }
}

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

    use super::*;

    #[test]
    fn test_replace_already_imported() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
use std::fs;

fn main() {
    std::f$0s::Path
}",
            r"
mod std { pub mod fs { pub struct Path; } }
use std::fs;

fn main() {
    fs::Path
}",
        )
    }

    #[test]
    fn test_replace_add_use_no_anchor() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
std::fs::Path$0
    ",
            r"
use std::fs::Path;

mod std { pub mod fs { pub struct Path; } }
Path
    ",
        );
    }

    #[test]
    fn test_replace_add_use_no_anchor_middle_segment() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fs { pub struct Path; } }
std::fs$0::Path
    ",
            r"
use std::fs;

mod std { pub mod fs { pub struct Path; } }
fs::Path
    ",
        );
    }

    #[test]
    fn dont_import_trivial_paths() {
        cov_mark::check!(dont_import_trivial_paths);
        check_assist_not_applicable(replace_qualified_name_with_use, r"impl foo$0 for () {}");
    }

    #[test]
    fn test_replace_not_applicable_in_use() {
        cov_mark::check!(not_applicable_in_use);
        check_assist_not_applicable(replace_qualified_name_with_use, r"use std::fmt$0;");
    }

    #[test]
    fn replaces_all_affected_paths() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    std::fmt::Debug$0;
    let x: std::fmt::Debug = std::fmt::Debug;
}
    ",
            r"
use std::fmt::Debug;

mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    Debug;
    let x: Debug = Debug;
}
    ",
        );
    }

    #[test]
    fn does_not_replace_in_submodules() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    std::fmt::Debug$0;
}

mod sub {
    fn f() {
        std::fmt::Debug;
    }
}
    ",
            r"
use std::fmt::Debug;

mod std { pub mod fmt { pub trait Debug {} } }
fn main() {
    Debug;
}

mod sub {
    fn f() {
        std::fmt::Debug;
    }
}
    ",
        );
    }

    #[test]
    fn does_not_replace_in_use() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std { pub mod fmt { pub trait Display {} } }
use std::fmt::Display;

fn main() {
    std::fmt$0;
}
    ",
            r"
mod std { pub mod fmt { pub trait Display {} } }
use std::fmt::{Display, self};

fn main() {
    fmt;
}
    ",
        );
    }

    #[test]
    fn does_not_replace_assoc_item_path() {
        check_assist_not_applicable(
            replace_qualified_name_with_use,
            r"
pub struct Foo;
impl Foo {
    pub fn foo() {}
}

fn main() {
    Foo::foo$0();
}
",
        );
    }

    #[test]
    fn replace_reuses_path_qualifier() {
        check_assist(
            replace_qualified_name_with_use,
            r"
pub mod foo {
    pub struct Foo;
}

mod bar {
    pub use super::foo::Foo as Bar;
}

fn main() {
    foo::Foo$0;
}
",
            r"
use foo::Foo;

pub mod foo {
    pub struct Foo;
}

mod bar {
    pub use super::foo::Foo as Bar;
}

fn main() {
    Foo;
}
",
        );
    }

    #[test]
    fn replace_does_not_always_try_to_replace_by_full_item_path() {
        check_assist(
            replace_qualified_name_with_use,
            r"
use std::mem;

mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    mem::drop$0(0);
}
",
            r"
use std::mem::{self, drop};

mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    drop(0);
}
",
        );
    }

    #[test]
    fn replace_should_drop_generic_args_in_use() {
        check_assist(
            replace_qualified_name_with_use,
            r"
mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    std::mem::drop::<usize>$0(0);
}
",
            r"
use std::mem::drop;

mod std {
    pub mod mem {
        pub fn drop<T>(_: T) {}
    }
}

fn main() {
    drop::<usize>(0);
}
",
        );
    }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) edef <edef@edef.eu>,
//               whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.
pub use self::imp::*;

// rust-lang/rust#25544
// #[cfg_attr(target_arch = "x86",    path = "x86.rs")]
// #[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
// mod imp;

#[cfg(target_arch = "x86")]
#[path = "x86.rs"]
mod imp;

#[cfg(target_arch = "x86_64")]
#[path = "x86_64.rs"]
mod imp;
<commit_msg>Remove workaround for rust-lang/rust#25544.<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) edef <edef@edef.eu>,
//               whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.

pub use self::imp::*;

#[allow(unused_attributes)] // rust-lang/rust#35584
#[cfg_attr(target_arch = "x86",    path = "x86.rs")]
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
mod imp;
<|endoftext|>


<commit_before>// Copyright (C) 2015 Élisabeth HENRY.
//
// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

extern crate caribon;
mod config;
use config::Config;
use caribon::Parser;

use std::error::Error;
use std::io;
use std::io::Read;
use std::io::BufRead;
use std::collections::HashMap;

fn print_stats(h: &HashMap<String, f32>, n_words: u32) {
    let different_words = h.len();
    println!("Number of words: {}", n_words);
    println!("Number of different words: {}", different_words);
}

fn try_parse() -> Result<(), Box<Error>> {
    let mut config = Config::new_from_args();
    let mut parser = try!(Parser::new(&config.lang));

    parser = parser.with_html(&config.input_format == "html")
                   .with_fuzzy(config.fuzzy)
                   .with_ignore_proper(config.ignore_proper)
                   .with_max_distance(config.max_distance);

    if !config.ignored.is_empty() {
        parser = parser.with_ignored(&config.ignored);
    }
    if !config.add_ignored.is_empty() {
        parser = parser.with_more_ignored(&config.add_ignored);
    }
    if !config.ispell {
        let mut s = String::new();
        try!(config.input.read_to_string(&mut s));

        let mut ast = try!(parser.tokenize(&s));
        if config.print_stats {
        let (h, count) = parser.words_stats(&ast);
            print_stats(&h, count);
        }
        parser.detect_local(&mut ast, config.threshold);
        if let Some(threshold) = config.global_threshold {
            parser.detect_global(&mut ast, threshold);
        }
        let output = match &*config.output_format {
            "html" => parser.ast_to_html(&mut ast, true),
            "terminal" => parser.ast_to_terminal(&ast),
            "markdown" => parser.ast_to_markdown(&ast),
            _ => return Err(Box::new(caribon::Error::new("Wrong output format: must be 'html, \
                                                          'terminal', or 'markdown'"))),
        };
        try!(config.output.write(&output.bytes().collect::<Vec<u8>>()));
        Ok(())
    } else {
        config::disguise_as_ispell();

        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            let mut ast = try!(parser.tokenize(&try!(line)));
            parser.detect_local(&mut ast, config.threshold);
            print!("{}", parser.ast_to_ispell(&ast, config.ispell_list));
            if !config.ispell_list {
                println!("");
            }
        }

        Ok(())
    }
}

fn main() {
    match try_parse() {
        Ok(_) => {}
        Err(e) => println!("{}", e.description()),
    }
}
<commit_msg>Work on ispell compatibility<commit_after>// Copyright (C) 2015 Élisabeth HENRY.
//
// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

extern crate caribon;
mod config;
use config::Config;
use caribon::Parser;

use std::error::Error;
use std::io;
use std::io::Read;
use std::io::Write;
use std::io::BufRead;
use std::collections::HashMap;
use std::fs::File;

fn print_stats(h: &HashMap<String, f32>, n_words: u32) {
    let different_words = h.len();
    println!("Number of words: {}", n_words);
    println!("Number of different words: {}", different_words);
}

fn try_parse() -> Result<(), Box<Error>> {
    let mut config = Config::new_from_args();
    let mut parser = try!(Parser::new(&config.lang));

    parser = parser.with_html(&config.input_format == "html")
                   .with_fuzzy(config.fuzzy)
                   .with_ignore_proper(config.ignore_proper)
                   .with_max_distance(config.max_distance);

    if !config.ignored.is_empty() {
        parser = parser.with_ignored(&config.ignored);
    }
    if !config.add_ignored.is_empty() {
        parser = parser.with_more_ignored(&config.add_ignored);
    }
    if !config.ispell {
        let mut s = String::new();
        try!(config.input.read_to_string(&mut s));

        let mut ast = try!(parser.tokenize(&s));
        if config.print_stats {
        let (h, count) = parser.words_stats(&ast);
            print_stats(&h, count);
        }
        parser.detect_local(&mut ast, config.threshold);
        if let Some(threshold) = config.global_threshold {
            parser.detect_global(&mut ast, threshold);
        }
        let output = match &*config.output_format {
            "html" => parser.ast_to_html(&mut ast, true),
            "terminal" => parser.ast_to_terminal(&ast),
            "markdown" => parser.ast_to_markdown(&ast),
            _ => return Err(Box::new(caribon::Error::new("Wrong output format: must be 'html, \
                                                          'terminal', or 'markdown'"))),
        };
        try!(config.output.write(&output.bytes().collect::<Vec<u8>>()));
        Ok(())
    } else {
        config::disguise_as_ispell();

        let stdin = io::stdin();
        let mut i = 0;
        for line in stdin.lock().lines() {
            i += 1;
            let mut line = try!(line);
            let first = if let Some(c) = line.chars().next() {
                c
            } else {
                continue;
            };
            match first {
                '!' => config.ispell_list = true, //terse mode
                '%' => config.ispell_list = false, //exit terse mode
                '*' | '@' | '#' | '~' | '+' | '-' => continue,
                '^' => line = (&line[1..]).to_owned(),
                _ => (),
            }
            let mut ast = try!(parser.tokenize(&line));
            parser.detect_local(&mut ast, config.threshold);
            let res = parser.ast_to_ispell(&ast, config.ispell_list);
            print!("{}", res);
            if !config.ispell_list {
                println!("");
            }
            let mut f = File::create(&format!("/tmp/caribon{}.log", i)).unwrap();
            f.write_all(&format!("input: {}\n***\noutput: {}\n", &line, res).as_bytes()).unwrap();
        }

        Ok(())
    }
}

fn main() {
    match try_parse() {
        Ok(_) => {}
        Err(e) => println!("{}", e.description()),
    }
}
<|endoftext|>


<commit_before>mod repl;

use repl::repl;

fn main() {
    repl();
}<commit_msg>placeholder for command line args<commit_after>mod repl;

use std::env;
use repl::repl;

fn main() {
    let mut args = env::args().skip(1);
    match args.next() {
        Some(f) => println!("{}", f),
        None    => repl(),
    };
}<|endoftext|>