<commit_before>use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::path::{Path, PathBuf};

use semver::VersionReq;
use serde::{Deserialize, Serialize};

use crate::core::package::PackageSet;
use crate::core::source::SourceMap;
use crate::core::PackageId;
use crate::core::{Dependency, Package, Source, SourceId};
use crate::sources::PathSource;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::{internal, Config, ToSemver};
use crate::util::{FileLock, Filesystem};

#[derive(Deserialize, Serialize)]
#[serde(untagged)]
pub enum CrateListing {
    V1(CrateListingV1),
    Empty(Empty),
}

#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Empty {}

#[derive(Deserialize, Serialize)]
pub struct CrateListingV1 {
    pub v1: BTreeMap<PackageId, BTreeSet<String>>,
}

pub fn resolve_root(flag: Option<&str>, config: &Config) -> CargoResult<Filesystem> {
    let config_root = config.get_path("install.root")?;
    Ok(flag
        .map(PathBuf::from)
        .or_else(|| env::var_os("CARGO_INSTALL_ROOT").map(PathBuf::from))
        .or_else(move || config_root.map(|v| v.val))
        .map(Filesystem::new)
        .unwrap_or_else(|| config.home().clone()))
}

pub fn path_source<'a>(source_id: SourceId, config: &'a Config) -> CargoResult<PathSource<'a>> {
    let path = source_id
        .url()
        .to_file_path()
        .map_err(|()| failure::format_err!("path sources must have a valid path"))?;
    Ok(PathSource::new(&path, source_id, config))
}

pub fn select_pkg<'a, T>(
    mut source: T,
    name: Option<&str>,
    vers: Option<&str>,
    config: &Config,
    needs_update: bool,
    list_all: &mut dyn FnMut(&mut T) -> CargoResult<Vec<Package>>,
) -> CargoResult<(Package, Box<dyn Source + 'a>)>
where
    T: Source + 'a,
{
    if needs_update {
        source.update()?;
    }

    match name {
        Some(name) => {
            let vers = match vers {
                Some(v) => {
                    // If the version begins with character <, >, =, ^, ~ parse it as a
                    // version range, otherwise parse it as a specific version
                    let first = v.chars().nth(0).ok_or_else(|| {
                        failure::format_err!("no version provided for the `--vers` flag")
                    })?;

                    match first {
                        '<' | '>' | '=' | '^' | '~' => match v.parse::<VersionReq>() {
                            Ok(v) => Some(v.to_string()),
                            Err(_) => failure::bail!(
                                "the `--vers` provided, `{}`, is \
                                       not a valid semver version requirement\n\n
                                       Please have a look at \
                                       http://doc.crates.io/specifying-dependencies.html \
                                       for the correct format",
                                v
                            ),
                        },
                        _ => match v.to_semver() {
                            Ok(v) => Some(format!("={}", v)),
                            Err(_) => {
                                let mut msg = format!(
                                    "\
                                     the `--vers` provided, `{}`, is \
                                     not a valid semver version\n\n\
                                     historically Cargo treated this \
                                     as a semver version requirement \
                                     accidentally\nand will continue \
                                     to do so, but this behavior \
                                     will be removed eventually",
                                    v
                                );

                                // If it is not a valid version but it is a valid version
                                // requirement, add a note to the warning
                                if v.parse::<VersionReq>().is_ok() {
                                    msg.push_str(&format!(
                                        "\nif you want to specify semver range, \
                                         add an explicit qualifier, like ^{}",
                                        v
                                    ));
                                }
                                config.shell().warn(&msg)?;
                                Some(v.to_string())
                            }
                        },
                    }
                }
                None => None,
            };
            let vers = vers.as_ref().map(|s| &**s);
            let vers_spec = if vers.is_none() && source.source_id().is_registry() {
                // Avoid pre-release versions from crate.io
                // unless explicitly asked for
                Some("*")
            } else {
                vers
            };
            let dep = Dependency::parse_no_deprecated(name, vers_spec, source.source_id())?;
            let deps = source.query_vec(&dep)?;
            let pkgid = match deps.iter().map(|p| p.package_id()).max() {
                Some(pkgid) => pkgid,
                None => {
                    let vers_info = vers
                        .map(|v| format!(" with version `{}`", v))
                        .unwrap_or_default();
                    failure::bail!(
                        "could not find `{}` in {}{}",
                        name,
                        source.source_id(),
                        vers_info
                    )
                }
            };

            let pkg = {
                let mut map = SourceMap::new();
                map.insert(Box::new(&mut source));
                PackageSet::new(&[pkgid], map, config)?
                    .get_one(pkgid)?
                    .clone()
            };
            Ok((pkg, Box::new(source)))
        }
        None => {
            let candidates = list_all(&mut source)?;
            let binaries = candidates
                .iter()
                .filter(|cand| cand.targets().iter().filter(|t| t.is_bin()).count() > 0);
            let examples = candidates
                .iter()
                .filter(|cand| cand.targets().iter().filter(|t| t.is_example()).count() > 0);
            let pkg = match one(binaries, |v| multi_err("binaries", v))? {
                Some(p) => p,
                None => match one(examples, |v| multi_err("examples", v))? {
                    Some(p) => p,
                    None => failure::bail!(
                        "no packages found with binaries or \
                         examples"
                    ),
                },
            };
            return Ok((pkg.clone(), Box::new(source)));

            fn multi_err(kind: &str, mut pkgs: Vec<&Package>) -> String {
                pkgs.sort_unstable_by_key(|a| a.name());
                format!(
                    "multiple packages with {} found: {}",
                    kind,
                    pkgs.iter()
                        .map(|p| p.name().as_str())
                        .collect::<Vec<_>>()
                        .join(", ")
                )
            }
        }
    }
}

pub fn one<I, F>(mut i: I, f: F) -> CargoResult<Option<I::Item>>
where
    I: Iterator,
    F: FnOnce(Vec<I::Item>) -> String,
{
    match (i.next(), i.next()) {
        (Some(i1), Some(i2)) => {
            let mut v = vec![i1, i2];
            v.extend(i);
            Err(failure::format_err!("{}", f(v)))
        }
        (Some(i), None) => Ok(Some(i)),
        (None, _) => Ok(None),
    }
}

pub fn read_crate_list(file: &FileLock) -> CargoResult<CrateListingV1> {
    let listing = (|| -> CargoResult<_> {
        let mut contents = String::new();
        file.file().read_to_string(&mut contents)?;
        let listing =
            toml::from_str(&contents).chain_err(|| internal("invalid TOML found for metadata"))?;
        match listing {
            CrateListing::V1(v1) => Ok(v1),
            CrateListing::Empty(_) => Ok(CrateListingV1 {
                v1: BTreeMap::new(),
            }),
        }
    })()
    .chain_err(|| {
        failure::format_err!(
            "failed to parse crate metadata at `{}`",
            file.path().to_string_lossy()
        )
    })?;
    Ok(listing)
}

pub fn write_crate_list(file: &FileLock, listing: CrateListingV1) -> CargoResult<()> {
    (|| -> CargoResult<_> {
        let mut file = file.file();
        file.seek(SeekFrom::Start(0))?;
        file.set_len(0)?;
        let data = toml::to_string(&CrateListing::V1(listing))?;
        file.write_all(data.as_bytes())?;
        Ok(())
    })()
    .chain_err(|| {
        failure::format_err!(
            "failed to write crate metadata at `{}`",
            file.path().to_string_lossy()
        )
    })?;
    Ok(())
}

pub fn metadata(config: &Config, root: &Filesystem) -> CargoResult<FileLock> {
    root.open_rw(Path::new(".crates.toml"), config, "crate metadata")
}
<commit_msg>fix: Make v1 field private<commit_after>use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::path::{Path, PathBuf};

use semver::VersionReq;
use serde::{Deserialize, Serialize};

use crate::core::package::PackageSet;
use crate::core::source::SourceMap;
use crate::core::PackageId;
use crate::core::{Dependency, Package, Source, SourceId};
use crate::sources::PathSource;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::{internal, Config, ToSemver};
use crate::util::{FileLock, Filesystem};

#[derive(Deserialize, Serialize)]
#[serde(untagged)]
pub enum CrateListing {
    V1(CrateListingV1),
    Empty(Empty),
}

#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Empty {}

#[derive(Deserialize, Serialize)]
pub struct CrateListingV1 {
    v1: BTreeMap<PackageId, BTreeSet<String>>,
}

pub fn resolve_root(flag: Option<&str>, config: &Config) -> CargoResult<Filesystem> {
    let config_root = config.get_path("install.root")?;
    Ok(flag
        .map(PathBuf::from)
        .or_else(|| env::var_os("CARGO_INSTALL_ROOT").map(PathBuf::from))
        .or_else(move || config_root.map(|v| v.val))
        .map(Filesystem::new)
        .unwrap_or_else(|| config.home().clone()))
}

pub fn path_source<'a>(source_id: SourceId, config: &'a Config) -> CargoResult<PathSource<'a>> {
    let path = source_id
        .url()
        .to_file_path()
        .map_err(|()| failure::format_err!("path sources must have a valid path"))?;
    Ok(PathSource::new(&path, source_id, config))
}

pub fn select_pkg<'a, T>(
    mut source: T,
    name: Option<&str>,
    vers: Option<&str>,
    config: &Config,
    needs_update: bool,
    list_all: &mut dyn FnMut(&mut T) -> CargoResult<Vec<Package>>,
) -> CargoResult<(Package, Box<dyn Source + 'a>)>
where
    T: Source + 'a,
{
    if needs_update {
        source.update()?;
    }

    match name {
        Some(name) => {
            let vers = match vers {
                Some(v) => {
                    // If the version begins with character <, >, =, ^, ~ parse it as a
                    // version range, otherwise parse it as a specific version
                    let first = v.chars().nth(0).ok_or_else(|| {
                        failure::format_err!("no version provided for the `--vers` flag")
                    })?;

                    match first {
                        '<' | '>' | '=' | '^' | '~' => match v.parse::<VersionReq>() {
                            Ok(v) => Some(v.to_string()),
                            Err(_) => failure::bail!(
                                "the `--vers` provided, `{}`, is \
                                       not a valid semver version requirement\n\n
                                       Please have a look at \
                                       http://doc.crates.io/specifying-dependencies.html \
                                       for the correct format",
                                v
                            ),
                        },
                        _ => match v.to_semver() {
                            Ok(v) => Some(format!("={}", v)),
                            Err(_) => {
                                let mut msg = format!(
                                    "\
                                     the `--vers` provided, `{}`, is \
                                     not a valid semver version\n\n\
                                     historically Cargo treated this \
                                     as a semver version requirement \
                                     accidentally\nand will continue \
                                     to do so, but this behavior \
                                     will be removed eventually",
                                    v
                                );

                                // If it is not a valid version but it is a valid version
                                // requirement, add a note to the warning
                                if v.parse::<VersionReq>().is_ok() {
                                    msg.push_str(&format!(
                                        "\nif you want to specify semver range, \
                                         add an explicit qualifier, like ^{}",
                                        v
                                    ));
                                }
                                config.shell().warn(&msg)?;
                                Some(v.to_string())
                            }
                        },
                    }
                }
                None => None,
            };
            let vers = vers.as_ref().map(|s| &**s);
            let vers_spec = if vers.is_none() && source.source_id().is_registry() {
                // Avoid pre-release versions from crate.io
                // unless explicitly asked for
                Some("*")
            } else {
                vers
            };
            let dep = Dependency::parse_no_deprecated(name, vers_spec, source.source_id())?;
            let deps = source.query_vec(&dep)?;
            let pkgid = match deps.iter().map(|p| p.package_id()).max() {
                Some(pkgid) => pkgid,
                None => {
                    let vers_info = vers
                        .map(|v| format!(" with version `{}`", v))
                        .unwrap_or_default();
                    failure::bail!(
                        "could not find `{}` in {}{}",
                        name,
                        source.source_id(),
                        vers_info
                    )
                }
            };

            let pkg = {
                let mut map = SourceMap::new();
                map.insert(Box::new(&mut source));
                PackageSet::new(&[pkgid], map, config)?
                    .get_one(pkgid)?
                    .clone()
            };
            Ok((pkg, Box::new(source)))
        }
        None => {
            let candidates = list_all(&mut source)?;
            let binaries = candidates
                .iter()
                .filter(|cand| cand.targets().iter().filter(|t| t.is_bin()).count() > 0);
            let examples = candidates
                .iter()
                .filter(|cand| cand.targets().iter().filter(|t| t.is_example()).count() > 0);
            let pkg = match one(binaries, |v| multi_err("binaries", v))? {
                Some(p) => p,
                None => match one(examples, |v| multi_err("examples", v))? {
                    Some(p) => p,
                    None => failure::bail!(
                        "no packages found with binaries or \
                         examples"
                    ),
                },
            };
            return Ok((pkg.clone(), Box::new(source)));

            fn multi_err(kind: &str, mut pkgs: Vec<&Package>) -> String {
                pkgs.sort_unstable_by_key(|a| a.name());
                format!(
                    "multiple packages with {} found: {}",
                    kind,
                    pkgs.iter()
                        .map(|p| p.name().as_str())
                        .collect::<Vec<_>>()
                        .join(", ")
                )
            }
        }
    }
}

pub fn one<I, F>(mut i: I, f: F) -> CargoResult<Option<I::Item>>
where
    I: Iterator,
    F: FnOnce(Vec<I::Item>) -> String,
{
    match (i.next(), i.next()) {
        (Some(i1), Some(i2)) => {
            let mut v = vec![i1, i2];
            v.extend(i);
            Err(failure::format_err!("{}", f(v)))
        }
        (Some(i), None) => Ok(Some(i)),
        (None, _) => Ok(None),
    }
}

pub fn read_crate_list(file: &FileLock) -> CargoResult<CrateListingV1> {
    let listing = (|| -> CargoResult<_> {
        let mut contents = String::new();
        file.file().read_to_string(&mut contents)?;
        let listing =
            toml::from_str(&contents).chain_err(|| internal("invalid TOML found for metadata"))?;
        match listing {
            CrateListing::V1(v1) => Ok(v1),
            CrateListing::Empty(_) => Ok(CrateListingV1 {
                v1: BTreeMap::new(),
            }),
        }
    })()
    .chain_err(|| {
        failure::format_err!(
            "failed to parse crate metadata at `{}`",
            file.path().to_string_lossy()
        )
    })?;
    Ok(listing)
}

pub fn write_crate_list(file: &FileLock, listing: CrateListingV1) -> CargoResult<()> {
    (|| -> CargoResult<_> {
        let mut file = file.file();
        file.seek(SeekFrom::Start(0))?;
        file.set_len(0)?;
        let data = toml::to_string(&CrateListing::V1(listing))?;
        file.write_all(data.as_bytes())?;
        Ok(())
    })()
    .chain_err(|| {
        failure::format_err!(
            "failed to write crate metadata at `{}`",
            file.path().to_string_lossy()
        )
    })?;
    Ok(())
}

pub fn metadata(config: &Config, root: &Filesystem) -> CargoResult<FileLock> {
    root.open_rw(Path::new(".crates.toml"), config, "crate metadata")
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]
// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

mod api;
mod files;

use serde_derive::Serialize;

use dotenv::dotenv;
use std::env;

use actix_web::{guard, middleware, web, App, Error as ActixError, HttpResponse, HttpServer};

use typed_html::elements::FlowContent;
use typed_html::types::Metadata;
use typed_html::{dom::DOMTree, html, text, OutputType};

use tinytemplate::TinyTemplate;

use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod};
use tokio_postgres::NoTls;

static TEMPLATE: &str = "Hello {name}!";

#[derive(Serialize)]
struct Context {
    name: String,
}

#[derive(Serialize, Debug)]
struct TemplateContext {
    parent: String,
    name: String,
    content: String,
    items: Vec<String>,
}

use std::path;
use std::process::Command;

async fn template(ssr: web::Path<bool>) -> Result<HttpResponse, ActixError> {
    let s2 = getStr();
    let s: String = if *ssr { s2.to_owned() } else { "".to_owned() };
    let context = TemplateContext {
        parent: "index".to_owned(),
        name: "Roman".to_owned(),
        content: s,
        items: vec!["One", "Two", "Three"]
            .iter()
            .map(|s| s.to_string())
            .collect(),
    };

    let doc: DOMTree<String> = doc(
        html!(

"Hello Kitty"

                    "She is not a cat. She is a human girl."

                { (0..3).map(|_| html!(

                        "Her name is Kitty White."

                )) }

                    "We still don't know how she eats."

"Hello Kitty"

                "DYNAMIC_CONTENT"

        ),
        context,
    );
    let mut doc_str = "<!doctype html>".to_owned() + &doc.to_string();

    // https://users.rust-lang.org/t/how-to-create-a-macro-from-dynamic-content/5079
    doc_str = doc_str.replacen("DYNAMIC_CONTENT", &s2, 1);

    Ok(HttpResponse::Ok().content_type("text/html").body(doc_str))
}

fn doc<T: OutputType + 'static + Send>(
    tree: Box<dyn FlowContent<T>>,
    context: TemplateContext,
) -> DOMTree<T> {
    let TemplateContext { name, items, .. } = context;
    html!(

                <title>"Hello Kitty"</title>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <link rel="icon" href="/favicon.ico?v=1" />
                <link href="/styles/normalize.css" rel="stylesheet" type="text/css" media="all" />
                <link href="/styles/style.css" rel="stylesheet" type="text/css" media="all" />
                <base href="/"></base>
                <meta name=Metadata::Author content="Not Sanrio Co., Ltd" />

{text!("{}", name)}

"Here are your items:"

                    {
                     items.iter().map(|item| html!(

{text!("{}", item)}

                     ))
                    }

                 { tree }

"Try going to ""/hello/YourName"

    )
}

use std::fs;
use std::fs::OpenOptions;
use std::io::prelude::*;

fn getStr() -> String {
    fs::copy(
        "../client/src/elm/Main.elm",
        "../client/src/elm/Main.elm.bak",
    )
    .expect("file not copied");
    let stdout: Vec<u8>;
    {
        let mut main_file = OpenOptions::new()
            .append(true)
            .open("../client/src/elm/Main.elm")
            .expect("file not opened");

        let str1 = format!(
            r#"
            view : Html Msg
            view =
                viewWithModel <|
                    Model [] HomeRoute <|
                        Flags "" {time} ""
            "#,
            time = time::OffsetDateTime::unix_epoch().second()
        );

        main_file
            .write_all(str1.as_bytes())
            .expect("file content not saved");

        stdout = Command::new("node")
            .current_dir(&path::Path::new("../client"))
            .arg("./node_modules/elm-static-html/index.js")
            .arg("-f")
            .arg("src/elm/Main.elm")
            .output()
            .expect("elm-static-html command failed to start")
            .stdout;
    }
    fs::rename(
        "../client/src/elm/Main.elm.bak",
        "../client/src/elm/Main.elm",
    )
    .expect("file not renamed");

    String::from_utf8_lossy(&*stdout)
        .lines()
        .skip_while(|x| x.find(r#"id="content""#).is_none())
        .collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv().ok();
    env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let endpoint = format!("127.0.0.1:{}", env::var("SERVER_PORT")?);

    let connection_string = format!(
        "postgres://{}:{}@{}:{}/{}",
        &env::var("DBUSER")?,
        &env::var("DBPASS")?,
        &env::var("DBHOST")?,
        &env::var("DBPORT")?,
        &env::var("DBNAME")?,
    );
    let pg_config: tokio_postgres::Config = connection_string.parse()?;
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast,
    };
    let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
    let pool = Pool::new(mgr, 16);

    let mut tt = TinyTemplate::new();
    tt.add_template("hello", TEMPLATE)?;

    let context = Context {
        name: "TinyTemplate".to_string(),
    };

    let rendered = tt.render("hello", &context)?;
    println!("{}", rendered);

    let sys = actix_rt::System::new("app");
    HttpServer::new(move || {
        App::new()
            .data(pool.clone())
            .wrap(middleware::Logger::default())
            .service(web::resource("/template/{ssr}").route(web::get().to(template)))
            .service(web::resource("/userInformation").route(web::get().to(api::user_information)))
            .service(web::resource("/dataSets").route(web::get().to(api::data_sets)))
            .service(web::resource("/dataSets/{url}").route(web::get().to(api::data_set)))
            .service(
                web::resource("/dataSetsCategories")
                    .route(web::get().to(api::data_sets_categories)),
            )
            .service(
                web::resource("/dataSetsCategories/{url}")
                    .route(web::get().to(api::data_set_category)),
            )
            .service(web::resource("/favicon").route(web::get().to(files::favicon)))
            .service(web::resource("/styles/{file:.*}").route(web::get().to(files::styles)))
            .service(web::resource("/js/{file:.*}").route(web::get().to(files::js)))
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(files::index))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind(&endpoint)?
    .run();
    // When main returns `Result<(), Box<dyn std::error::Error + 'static + Send + Sync>> instead of
    // `io::Result<()>`, there is error and `into()` is needed.
    // expected struct `std::boxed::Box`, found struct `std::io::Error`
    // https://users.rust-lang.org/t/boxing-errors-in-result-throws-type-mismatch/36692/2
    //.map_err(|e| e.into())

    println!("Server running at {:?}", endpoint);
    let _ = sys.run();

    Ok(())
}
<commit_msg>Clarification of returning Ok(())<commit_after>#![recursion_limit = "256"]
// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

mod api;
mod files;

use serde_derive::Serialize;

use dotenv::dotenv;
use std::env;

use actix_web::{guard, middleware, web, App, Error as ActixError, HttpResponse, HttpServer};

use typed_html::elements::FlowContent;
use typed_html::types::Metadata;
use typed_html::{dom::DOMTree, html, text, OutputType};

use tinytemplate::TinyTemplate;

use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod};
use tokio_postgres::NoTls;

static TEMPLATE: &str = "Hello {name}!";

#[derive(Serialize)]
struct Context {
    name: String,
}

#[derive(Serialize, Debug)]
struct TemplateContext {
    parent: String,
    name: String,
    content: String,
    items: Vec<String>,
}

use std::path;
use std::process::Command;

async fn template(ssr: web::Path<bool>) -> Result<HttpResponse, ActixError> {
    let s2 = getStr();
    let s: String = if *ssr { s2.to_owned() } else { "".to_owned() };
    let context = TemplateContext {
        parent: "index".to_owned(),
        name: "Roman".to_owned(),
        content: s,
        items: vec!["One", "Two", "Three"]
            .iter()
            .map(|s| s.to_string())
            .collect(),
    };

    let doc: DOMTree<String> = doc(
        html!(

"Hello Kitty"

                            "She is not a cat. She is a human girl."

                        { (0..3).map(|_| html!(

                                "Her name is Kitty White."

                        )) }

                            "We still don't know how she eats."

"Hello Kitty"

                        "DYNAMIC_CONTENT"

                ),
        context,
    );
    let mut doc_str = "<!doctype html>".to_owned() + &doc.to_string();

    // https://users.rust-lang.org/t/how-to-create-a-macro-from-dynamic-content/5079
    doc_str = doc_str.replacen("DYNAMIC_CONTENT", &s2, 1);

    Ok(HttpResponse::Ok().content_type("text/html").body(doc_str))
}

fn doc<T: OutputType + 'static + Send>(
    tree: Box<dyn FlowContent<T>>,
    context: TemplateContext,
) -> DOMTree<T> {
    let TemplateContext { name, items, .. } = context;
    html!(

                <title>"Hello Kitty"</title>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <link rel="icon" href="/favicon.ico?v=1" />
                <link href="/styles/normalize.css" rel="stylesheet" type="text/css" media="all" />
                <link href="/styles/style.css" rel="stylesheet" type="text/css" media="all" />
                <base href="/"></base>
                <meta name=Metadata::Author content="Not Sanrio Co., Ltd" />

{text!("{}", name)}

"Here are your items:"

                    {
                     items.iter().map(|item| html!(

{text!("{}", item)}

                     ))
                    }

                 { tree }

"Try going to ""/hello/YourName"

    )
}

use std::fs;
use std::fs::OpenOptions;
use std::io::prelude::*;

fn getStr() -> String {
    fs::copy(
        "../client/src/elm/Main.elm",
        "../client/src/elm/Main.elm.bak",
    )
    .expect("file not copied");
    let stdout: Vec<u8>;
    {
        let mut main_file = OpenOptions::new()
            .append(true)
            .open("../client/src/elm/Main.elm")
            .expect("file not opened");

        let str1 = format!(
            r#"
            view : Html Msg
            view =
                viewWithModel <|
                    Model [] HomeRoute <|
                        Flags "" {time} ""
            "#,
            time = time::OffsetDateTime::unix_epoch().second()
        );

        main_file
            .write_all(str1.as_bytes())
            .expect("file content not saved");

        stdout = Command::new("node")
            .current_dir(&path::Path::new("../client"))
            .arg("./node_modules/elm-static-html/index.js")
            .arg("-f")
            .arg("src/elm/Main.elm")
            .output()
            .expect("elm-static-html command failed to start")
            .stdout;
    }
    fs::rename(
        "../client/src/elm/Main.elm.bak",
        "../client/src/elm/Main.elm",
    )
    .expect("file not renamed");

    String::from_utf8_lossy(&*stdout)
        .lines()
        .skip_while(|x| x.find(r#"id="content""#).is_none())
        .collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv().ok();
    env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let endpoint = format!("127.0.0.1:{}", env::var("SERVER_PORT")?);

    let connection_string = format!(
        "postgres://{}:{}@{}:{}/{}",
        &env::var("DBUSER")?,
        &env::var("DBPASS")?,
        &env::var("DBHOST")?,
        &env::var("DBPORT")?,
        &env::var("DBNAME")?,
    );
    let pg_config: tokio_postgres::Config = connection_string.parse()?;
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast,
    };
    let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
    let pool = Pool::new(mgr, 16);

    let mut tt = TinyTemplate::new();
    tt.add_template("hello", TEMPLATE)?;

    let context = Context {
        name: "TinyTemplate".to_string(),
    };

    let rendered = tt.render("hello", &context)?;
    println!("{}", rendered);

    let sys = actix_rt::System::new("app");
    HttpServer::new(move || {
        App::new()
            .data(pool.clone())
            .wrap(middleware::Logger::default())
            .service(web::resource("/template/{ssr}").route(web::get().to(template)))
            .service(web::resource("/userInformation").route(web::get().to(api::user_information)))
            .service(web::resource("/dataSets").route(web::get().to(api::data_sets)))
            .service(web::resource("/dataSets/{url}").route(web::get().to(api::data_set)))
            .service(
                web::resource("/dataSetsCategories")
                    .route(web::get().to(api::data_sets_categories)),
            )
            .service(
                web::resource("/dataSetsCategories/{url}")
                    .route(web::get().to(api::data_set_category)),
            )
            .service(web::resource("/favicon").route(web::get().to(files::favicon)))
            .service(web::resource("/styles/{file:.*}").route(web::get().to(files::styles)))
            .service(web::resource("/js/{file:.*}").route(web::get().to(files::js)))
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(files::index))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind(&endpoint)?
    .run();
    // If you do not return `Ok(())` but just `.run()`, this will happend:
    // When main returns `Result<(), Box<dyn std::error::Error + 'static + Send + Sync>> instead of
    // `io::Result<()>`, there is error and `into()` is needed.
    // expected struct `std::boxed::Box`, found struct `std::io::Error`
    // https://users.rust-lang.org/t/boxing-errors-in-result-throws-type-mismatch/36692/2
    //.map_err(|e| e.into())

    println!("Server running at {:?}", endpoint);
    let _ = sys.run();

    Ok(())
}
<|endoftext|>


<commit_before>use base64;
use crypto;
use crypto::digest::Digest;
use crypto::mac::Mac;
use futures::sync::mpsc;
use futures::{Future, Poll, Stream};
use hyper::server::{Http, Request, Response, Service};
use hyper::{self, Get, Post, StatusCode};

#[cfg(feature = "with-dns-sd")]
use dns_sd::DNSService;

#[cfg(not(feature = "with-dns-sd"))]
use mdns;

use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
use std::io;
use std::sync::Arc;
use tokio_core::reactor::Handle;
use url;

use core::authentication::Credentials;
use core::config::ConnectConfig;
use core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
use core::util;

#[derive(Clone)]
struct Discovery(Arc<DiscoveryInner>);
struct DiscoveryInner {
    config: ConnectConfig,
    device_id: String,
    private_key: BigUint,
    public_key: BigUint,
    tx: mpsc::UnboundedSender<Credentials>,
}

impl Discovery {
    fn new(
        config: ConnectConfig,
        device_id: String,
    ) -> (Discovery, mpsc::UnboundedReceiver<Credentials>) {
        let (tx, rx) = mpsc::unbounded();

        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        let discovery = Discovery(Arc::new(DiscoveryInner {
            config: config,
            device_id: device_id,
            private_key: private_key,
            public_key: public_key,
            tx: tx,
        }));

        (discovery, rx)
    }
}

impl Discovery {
    fn handle_get_info(
        &self,
        _params: &BTreeMap<String, String>,
    ) -> ::futures::Finished<Response, hyper::Error> {
        let public_key = self.0.public_key.to_bytes_be();
        let public_key = base64::encode(&public_key);

        let result = json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.1.0",
            "deviceID": (self.0.device_id),
            "remoteName": (self.0.config.name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": (self.0.config.device_type.to_string().to_uppercase()),
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
        });

        let body = result.to_string();
        ::futures::finished(Response::new().with_body(body))
    }

    fn handle_add_user(
        &self,
        params: &BTreeMap<String, String>,
    ) -> ::futures::Finished<Response, hyper::Error> {
        let username = params.get("userName").unwrap();
        let encrypted_blob = params.get("blob").unwrap();
        let client_key = params.get("clientKey").unwrap();

        let encrypted_blob = base64::decode(encrypted_blob).unwrap();

        let client_key = base64::decode(client_key).unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20];
        let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()];

        let base_key = {
            let mut data = [0u8; 20];
            let mut h = crypto::sha1::Sha1::new();
            h.input(&shared_key.to_bytes_be());
            h.result(&mut data);
            data[..16].to_owned()
        };

        let checksum_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input(b"checksum");
            h.result().code().to_owned()
        };

        let encryption_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input(b"encryption");
            h.result().code().to_owned()
        };

        let mac = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &checksum_key);
            h.input(encrypted);
            h.result().code().to_owned()
        };

        if mac != cksum {
            warn!("Login error for user {:?}: MAC mismatch", username);
            let result = json!({
                "status": 102,
                "spotifyError": 1,
                "statusString": "ERROR-MAC"
            });

            let body = result.to_string();
            return ::futures::finished(Response::new().with_body(body))
        }

        let decrypted = {
            let mut data = vec![0u8; encrypted.len()];
            let mut cipher =
                crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key[0..16], iv);
            cipher.process(encrypted, &mut data);
            String::from_utf8(data).unwrap()
        };

        let credentials = Credentials::with_blob(username.to_owned(), &decrypted, &self.0.device_id);

        self.0.tx.unbounded_send(credentials).unwrap();

        let result = json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        });

        let body = result.to_string();
        ::futures::finished(Response::new().with_body(body))
    }

    fn not_found(&self) -> ::futures::Finished<Response, hyper::Error> {
        ::futures::finished(Response::new().with_status(StatusCode::NotFound))
    }
}

impl Service for Discovery {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Response, Error = hyper::Error>>;

    fn call(&self, request: Request) -> Self::Future {
        let mut params = BTreeMap::new();

        let (method, uri, _, _, body) = request.deconstruct();
        if let Some(query) = uri.query() {
            params.extend(url::form_urlencoded::parse(query.as_bytes()).into_owned());
        }

        if method != Get {
            debug!("{:?} {:?} {:?}", method, uri.path(), params);
        }

        let this = self.clone();
        Box::new(
            body.fold(Vec::new(), |mut acc, chunk| {
                acc.extend_from_slice(chunk.as_ref());
                Ok::<_, hyper::Error>(acc)
            }).map(move |body| {
                    params.extend(url::form_urlencoded::parse(&body).into_owned());
                    params
                })
                .and_then(
                    move |params| match (method, params.get("action").map(AsRef::as_ref)) {
                        (Get, Some("getInfo")) => this.handle_get_info(&params),
                        (Post, Some("addUser")) => this.handle_add_user(&params),
                        _ => this.not_found(),
                    },
                ),
        )
    }
}

#[cfg(feature = "with-dns-sd")]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: DNSService,
}

#[cfg(not(feature = "with-dns-sd"))]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: mdns::Service,
}

pub fn discovery(
    handle: &Handle,
    config: ConnectConfig,
    device_id: String,
    port: u16,
) -> io::Result<DiscoveryStream> {
    let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

    let serve = {
        let http = Http::new();
        debug!("Zeroconf server listening on 0.0.0.0:{}", port);
        http.serve_addr_handle(
            &format!("0.0.0.0:{}", port).parse().unwrap(),
            &handle,
            move || Ok(discovery.clone()),
        ).unwrap()
    };

    let s_port = serve.incoming_ref().local_addr().port();

    let server_future = {
        let handle = handle.clone();
        serve
            .for_each(move |connection| {
                handle.spawn(connection.then(|_| Ok(())));
                Ok(())
            })
            .then(|_| Ok(()))
    };
    handle.spawn(server_future);

    #[cfg(feature = "with-dns-sd")]
    let svc = DNSService::register(
        Some(&*config.name),
        "_spotify-connect._tcp",
        None,
        None,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    ).unwrap();

    #[cfg(not(feature = "with-dns-sd"))]
    let responder = mdns::Responder::spawn(&handle)?;

    #[cfg(not(feature = "with-dns-sd"))]
    let svc = responder.register(
        "_spotify-connect._tcp".to_owned(),
        config.name,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    );

    Ok(DiscoveryStream {
        credentials: creds_rx,
        _svc: svc,
    })
}

impl Stream for DiscoveryStream {
    type Item = Credentials;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.credentials.poll()
    }
}
<commit_msg>discover: log the actual HTTP port that is used.<commit_after>use base64;
use crypto;
use crypto::digest::Digest;
use crypto::mac::Mac;
use futures::sync::mpsc;
use futures::{Future, Poll, Stream};
use hyper::server::{Http, Request, Response, Service};
use hyper::{self, Get, Post, StatusCode};

#[cfg(feature = "with-dns-sd")]
use dns_sd::DNSService;

#[cfg(not(feature = "with-dns-sd"))]
use mdns;

use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
use std::io;
use std::sync::Arc;
use tokio_core::reactor::Handle;
use url;

use core::authentication::Credentials;
use core::config::ConnectConfig;
use core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
use core::util;

#[derive(Clone)]
struct Discovery(Arc<DiscoveryInner>);
struct DiscoveryInner {
    config: ConnectConfig,
    device_id: String,
    private_key: BigUint,
    public_key: BigUint,
    tx: mpsc::UnboundedSender<Credentials>,
}

impl Discovery {
    fn new(
        config: ConnectConfig,
        device_id: String,
    ) -> (Discovery, mpsc::UnboundedReceiver<Credentials>) {
        let (tx, rx) = mpsc::unbounded();

        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        let discovery = Discovery(Arc::new(DiscoveryInner {
            config: config,
            device_id: device_id,
            private_key: private_key,
            public_key: public_key,
            tx: tx,
        }));

        (discovery, rx)
    }
}

impl Discovery {
    fn handle_get_info(
        &self,
        _params: &BTreeMap<String, String>,
    ) -> ::futures::Finished<Response, hyper::Error> {
        let public_key = self.0.public_key.to_bytes_be();
        let public_key = base64::encode(&public_key);

        let result = json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.1.0",
            "deviceID": (self.0.device_id),
            "remoteName": (self.0.config.name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": (self.0.config.device_type.to_string().to_uppercase()),
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
        });

        let body = result.to_string();
        ::futures::finished(Response::new().with_body(body))
    }

    fn handle_add_user(
        &self,
        params: &BTreeMap<String, String>,
    ) -> ::futures::Finished<Response, hyper::Error> {
        let username = params.get("userName").unwrap();
        let encrypted_blob = params.get("blob").unwrap();
        let client_key = params.get("clientKey").unwrap();

        let encrypted_blob = base64::decode(encrypted_blob).unwrap();

        let client_key = base64::decode(client_key).unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20];
        let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()];

        let base_key = {
            let mut data = [0u8; 20];
            let mut h = crypto::sha1::Sha1::new();
            h.input(&shared_key.to_bytes_be());
            h.result(&mut data);
            data[..16].to_owned()
        };

        let checksum_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input(b"checksum");
            h.result().code().to_owned()
        };

        let encryption_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input(b"encryption");
            h.result().code().to_owned()
        };

        let mac = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &checksum_key);
            h.input(encrypted);
            h.result().code().to_owned()
        };

        if mac != cksum {
            warn!("Login error for user {:?}: MAC mismatch", username);
            let result = json!({
                "status": 102,
                "spotifyError": 1,
                "statusString": "ERROR-MAC"
            });

            let body = result.to_string();
            return ::futures::finished(Response::new().with_body(body))
        }

        let decrypted = {
            let mut data = vec![0u8; encrypted.len()];
            let mut cipher =
                crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key[0..16], iv);
            cipher.process(encrypted, &mut data);
            String::from_utf8(data).unwrap()
        };

        let credentials = Credentials::with_blob(username.to_owned(), &decrypted, &self.0.device_id);

        self.0.tx.unbounded_send(credentials).unwrap();

        let result = json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        });

        let body = result.to_string();
        ::futures::finished(Response::new().with_body(body))
    }

    fn not_found(&self) -> ::futures::Finished<Response, hyper::Error> {
        ::futures::finished(Response::new().with_status(StatusCode::NotFound))
    }
}

impl Service for Discovery {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Response, Error = hyper::Error>>;

    fn call(&self, request: Request) -> Self::Future {
        let mut params = BTreeMap::new();

        let (method, uri, _, _, body) = request.deconstruct();
        if let Some(query) = uri.query() {
            params.extend(url::form_urlencoded::parse(query.as_bytes()).into_owned());
        }

        if method != Get {
            debug!("{:?} {:?} {:?}", method, uri.path(), params);
        }

        let this = self.clone();
        Box::new(
            body.fold(Vec::new(), |mut acc, chunk| {
                acc.extend_from_slice(chunk.as_ref());
                Ok::<_, hyper::Error>(acc)
            }).map(move |body| {
                    params.extend(url::form_urlencoded::parse(&body).into_owned());
                    params
                })
                .and_then(
                    move |params| match (method, params.get("action").map(AsRef::as_ref)) {
                        (Get, Some("getInfo")) => this.handle_get_info(&params),
                        (Post, Some("addUser")) => this.handle_add_user(&params),
                        _ => this.not_found(),
                    },
                ),
        )
    }
}

#[cfg(feature = "with-dns-sd")]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: DNSService,
}

#[cfg(not(feature = "with-dns-sd"))]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: mdns::Service,
}

pub fn discovery(
    handle: &Handle,
    config: ConnectConfig,
    device_id: String,
    port: u16,
) -> io::Result<DiscoveryStream> {
    let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

    let serve = {
        let http = Http::new();
        http.serve_addr_handle(
            &format!("0.0.0.0:{}", port).parse().unwrap(),
            &handle,
            move || Ok(discovery.clone()),
        ).unwrap()
    };

    let s_port = serve.incoming_ref().local_addr().port();
    debug!("Zeroconf server listening on 0.0.0.0:{}", s_port);

    let server_future = {
        let handle = handle.clone();
        serve
            .for_each(move |connection| {
                handle.spawn(connection.then(|_| Ok(())));
                Ok(())
            })
            .then(|_| Ok(()))
    };
    handle.spawn(server_future);

    #[cfg(feature = "with-dns-sd")]
    let svc = DNSService::register(
        Some(&*config.name),
        "_spotify-connect._tcp",
        None,
        None,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    ).unwrap();

    #[cfg(not(feature = "with-dns-sd"))]
    let responder = mdns::Responder::spawn(&handle)?;

    #[cfg(not(feature = "with-dns-sd"))]
    let svc = responder.register(
        "_spotify-connect._tcp".to_owned(),
        config.name,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    );

    Ok(DiscoveryStream {
        credentials: creds_rx,
        _svc: svc,
    })
}

impl Stream for DiscoveryStream {
    type Item = Credentials;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.credentials.poll()
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

extern crate sapper;
extern crate env_logger;
#[macro_use]
extern crate log;

use sapper::SapperApp;

mod biz;
use biz::Biz;
mod foo;
use foo::Foo;

pub fn main() {
    env_logger::init().unwrap();

    let mut sapp = SapperApp::new();
    sapp.address("127.0.0.1")
        .port(1337)
        .add_module(Box::new(Biz))
        .add_module(Box::new(Foo));

    println!("Listening on http://127.0.0.1:1337");
    sapp.run_http();

}
<commit_msg>remove some blank lines.<commit_after>#![allow(unused_variables)]

extern crate sapper;
extern crate env_logger;
#[macro_use]
extern crate log;

use sapper::SapperApp;

mod biz;
use biz::Biz;
mod foo;
use foo::Foo;

pub fn main() {
    env_logger::init().unwrap();

    let mut sapp = SapperApp::new();
    sapp.address("127.0.0.1")
        .port(1337)
        .add_module(Box::new(Biz))
        .add_module(Box::new(Foo));

    println!("Listening on http://127.0.0.1:1337");
    sapp.run_http();

}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animatable=False)}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
${helpers.single_keyword("list-style-type", """
    disc none circle square decimal lower-alpha upper-alpha  disclosure-open disclosure-closed
""", extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari
                           gujarati gurmukhi kannada khmer lao malayalam mongolian
                           myanmar oriya persian telugu thai tibetan cjk-earthly-branch
                           cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana
                           katakana-iroha""",
    gecko_constant_prefix="NS_STYLE_LIST_STYLE",
    animatable=False)}

${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_)",
                          animatable="False")}

<%helpers:longhand name="quotes" animatable="False">
    use cssparser::Token;
    use std::borrow::Cow;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::NoViewportPercentage;

    pub use self::computed_value::T as SpecifiedValue;

    pub mod computed_value {
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T(pub Vec<(String,String)>);
    }

    impl ComputedValueAsSpecified for SpecifiedValue {}
    impl NoViewportPercentage for SpecifiedValue {}

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut first = true;
            for pair in &self.0 {
                if !first {
                    try!(dest.write_str(" "));
                }
                first = false;
                try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest));
                try!(dest.write_str(" "));
                try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest));
            }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(vec![
            ("\u{201c}".to_owned(), "\u{201d}".to_owned()),
            ("\u{2018}".to_owned(), "\u{2019}".to_owned()),
        ])
    }

    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(SpecifiedValue(Vec::new()))
        }

        let mut quotes = Vec::new();
        loop {
            let first = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                Ok(_) => return Err(()),
                Err(()) => break,
            };
            let second = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                _ => return Err(()),
            };
            quotes.push((first, second))
        }
        if !quotes.is_empty() {
            Ok(SpecifiedValue(quotes))
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<commit_msg>Move {lower,upper}-alpha to extra_servo_values<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animatable=False)}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
${helpers.single_keyword("list-style-type", """
    disc none circle square decimal disclosure-open disclosure-closed
""", extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari
                           gujarati gurmukhi kannada khmer lao malayalam mongolian
                           myanmar oriya persian telugu thai tibetan cjk-earthly-branch
                           cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana
                           katakana-iroha lower-alpha upper-alpha""",
    gecko_constant_prefix="NS_STYLE_LIST_STYLE",
    animatable=False)}

${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_)",
                          animatable="False")}

<%helpers:longhand name="quotes" animatable="False">
    use cssparser::Token;
    use std::borrow::Cow;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::NoViewportPercentage;

    pub use self::computed_value::T as SpecifiedValue;

    pub mod computed_value {
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T(pub Vec<(String,String)>);
    }

    impl ComputedValueAsSpecified for SpecifiedValue {}
    impl NoViewportPercentage for SpecifiedValue {}

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut first = true;
            for pair in &self.0 {
                if !first {
                    try!(dest.write_str(" "));
                }
                first = false;
                try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest));
                try!(dest.write_str(" "));
                try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest));
            }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(vec![
            ("\u{201c}".to_owned(), "\u{201d}".to_owned()),
            ("\u{2018}".to_owned(), "\u{2019}".to_owned()),
        ])
    }

    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(SpecifiedValue(Vec::new()))
        }

        let mut quotes = Vec::new();
        loop {
            let first = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                Ok(_) => return Err(()),
                Err(()) => break,
            };
            let second = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                _ => return Err(()),
            };
            quotes.push((first, second))
        }
        if !quotes.is_empty() {
            Ok(SpecifiedValue(quotes))
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<|endoftext|>


<commit_before>use hir::AsName;
use syntax::{
    ast::{self, edit::AstNodeEdit, make},
    AstNode,
};
use test_utils::mark;

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

// Assist: extract_assignment
//
// Extracts variable assigment to outside an if or match statement.
//
// ```
// fn main() {
//     let mut foo = 6;
//
//     if true {
//         <|>foo = 5;
//     } else {
//         foo = 4;
//     }
// }
// ```
// ->
// ```
// fn main() {
//     let mut foo = 6;
//
//     foo = if true {
//         5
//     } else {
//         4
//     };
// }
// ```
pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name();

    let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
        (
            ast::Expr::cast(if_expr.syntax().to_owned())?,
            exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()),
        )
    } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
        (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?)
    } else {
        return None;
    };

    let expr_stmt = make::expr_stmt(new_stmt);

    acc.add(
        AssistId("extract_assignment", AssistKind::RefactorExtract),
        "Extract assignment",
        old_stmt.syntax().text_range(),
        move |edit| {
            edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt));
        },
    )
}

fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> {
    let new_arm_list = match_expr
        .match_arm_list()?
        .arms()
        .map(|arm| {
            if let ast::Expr::BlockExpr(block) = arm.expr()? {
                let new_block = exprify_block(&block, name)?.indent(block.indent_level());
                Some(arm.replace_descendant(block, new_block))
            } else {
                None
            }
        })
        .collect::<Option<Vec<_>>>()?;
    let new_arm_list = match_expr
        .match_arm_list()?
        .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list));
    Some(make::expr_match(match_expr.expr()?, new_arm_list))
}

fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> {
    let then_branch = exprify_block(&statement.then_branch()?, name)?;
    let else_branch = match statement.else_branch()? {
        ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?),
        ast::ElseBranch::IfExpr(expr) => {
            mark::hit!(test_extract_assigment_chained_if);
            ast::ElseBranch::IfExpr(ast::IfExpr::cast(
                exprify_if(&expr, name)?.syntax().to_owned(),
            )?)
        }
    };
    Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch)))
}

fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> {
    if block.expr().is_some() {
        return None;
    }

    let mut stmts: Vec<_> = block.statements().collect();
    let stmt = stmts.pop()?;

    if let ast::Stmt::ExprStmt(stmt) = stmt {
        if let ast::Expr::BinExpr(expr) = stmt.expr()? {
            if expr.op_kind()? == ast::BinOp::Assignment
                && &expr.lhs()?.name_ref()?.as_name() == name
            {
                // The last statement in the block is an assignment to the name we want
                return Some(make::block_expr(stmts, Some(expr.rhs()?)));
            }
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;

    use crate::tests::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_extract_assignment_if() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else {
        a = 3;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        2
    } else {
        3
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assignment_match() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    match 1 {
        1 => {
            <|>a = 2;
        },
        2 => {
            a = 3;
        },
        3 => {
            a = 4;
        }
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = match 1 {
        1 => {
            2
        },
        2 => {
            3
        },
        3 => {
            4
        }
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assignment_not_last_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
        b = a;
    } else {
        a = 3;
    }
}"#,
        )
    }

    #[test]
    fn test_extract_assignment_chained_if() {
        mark::check!(test_extract_assigment_chained_if);
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else if false {
        a = 3;
    } else {
        a = 4;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        2
    } else if false {
        3
    } else {
        4
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assigment_retains_stmts() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        let b = 2;
        <|>a = 2;
    } else {
        let b = 3;
        a = 3;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        let b = 2;
        2
    } else {
        let b = 3;
        3
    };
}"#,
        )
    }

    #[test]
    fn extract_assignment_let_stmt_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    let b = if true {
        <|>a = 2
    } else {
        a = 3
    };
}"#,
        )
    }

    #[test]
    fn extract_assignment_if_missing_assigment_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else {}
}"#,
        )
    }

    #[test]
    fn extract_assignment_match_missing_assigment_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    match 1 {
        1 => {
            <|>a = 2;
        },
        2 => {
            a = 3;
        },
        3 => {},
    }
}"#,
        )
    }
}
<commit_msg>Support assignment to FieldExpr for extract_assignment assist<commit_after>use syntax::{
    ast::{self, edit::AstNodeEdit, make},
    AstNode,
};
use test_utils::mark;

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

// Assist: extract_assignment
//
// Extracts variable assigment to outside an if or match statement.
//
// ```
// fn main() {
//     let mut foo = 6;
//
//     if true {
//         <|>foo = 5;
//     } else {
//         foo = 4;
//     }
// }
// ```
// ->
// ```
// fn main() {
//     let mut foo = 6;
//
//     foo = if true {
//         5
//     } else {
//         4
//     };
// }
// ```
pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
    let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment {
        assign_expr.lhs()?
    } else {
        return None;
    };

    let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
        (
            ast::Expr::cast(if_expr.syntax().to_owned())?,
            exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()),
        )
    } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
        (
            ast::Expr::cast(match_expr.syntax().to_owned())?,
            exprify_match(&match_expr, &ctx.sema, &name_expr)?,
        )
    } else {
        return None;
    };

    let expr_stmt = make::expr_stmt(new_stmt);

    acc.add(
        AssistId("extract_assignment", AssistKind::RefactorExtract),
        "Extract assignment",
        old_stmt.syntax().text_range(),
        move |edit| {
            edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt));
        },
    )
}

fn exprify_match(
    match_expr: &ast::MatchExpr,
    sema: &hir::Semantics<ide_db::RootDatabase>,
    name: &ast::Expr,
) -> Option<ast::Expr> {
    let new_arm_list = match_expr
        .match_arm_list()?
        .arms()
        .map(|arm| {
            if let ast::Expr::BlockExpr(block) = arm.expr()? {
                let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level());
                Some(arm.replace_descendant(block, new_block))
            } else {
                None
            }
        })
        .collect::<Option<Vec<_>>>()?;
    let new_arm_list = match_expr
        .match_arm_list()?
        .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list));
    Some(make::expr_match(match_expr.expr()?, new_arm_list))
}

fn exprify_if(
    statement: &ast::IfExpr,
    sema: &hir::Semantics<ide_db::RootDatabase>,
    name: &ast::Expr,
) -> Option<ast::Expr> {
    let then_branch = exprify_block(&statement.then_branch()?, sema, name)?;
    let else_branch = match statement.else_branch()? {
        ast::ElseBranch::Block(ref block) => {
            ast::ElseBranch::Block(exprify_block(block, sema, name)?)
        }
        ast::ElseBranch::IfExpr(expr) => {
            mark::hit!(test_extract_assigment_chained_if);
            ast::ElseBranch::IfExpr(ast::IfExpr::cast(
                exprify_if(&expr, sema, name)?.syntax().to_owned(),
            )?)
        }
    };
    Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch)))
}

fn exprify_block(
    block: &ast::BlockExpr,
    sema: &hir::Semantics<ide_db::RootDatabase>,
    name: &ast::Expr,
) -> Option<ast::BlockExpr> {
    if block.expr().is_some() {
        return None;
    }

    let mut stmts: Vec<_> = block.statements().collect();
    let stmt = stmts.pop()?;

    if let ast::Stmt::ExprStmt(stmt) = stmt {
        if let ast::Expr::BinExpr(expr) = stmt.expr()? {
            if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name)
            {
                // The last statement in the block is an assignment to the name we want
                return Some(make::block_expr(stmts, Some(expr.rhs()?)));
            }
        }
    }
    None
}

fn is_equivalent(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    expr0: &ast::Expr,
    expr1: &ast::Expr,
) -> bool {
    match (expr0, expr1) {
        (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => {
            mark::hit!(test_extract_assignment_field_assignment);
            sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1)
        }
        (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => {
            let path0 = path0.path();
            let path1 = path1.path();
            if let (Some(path0), Some(path1)) = (path0, path1) {
                sema.resolve_path(&path0) == sema.resolve_path(&path1)
            } else {
                false
            }
        }
        _ => false,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use crate::tests::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_extract_assignment_if() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else {
        a = 3;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        2
    } else {
        3
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assignment_match() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    match 1 {
        1 => {
            <|>a = 2;
        },
        2 => {
            a = 3;
        },
        3 => {
            a = 4;
        }
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = match 1 {
        1 => {
            2
        },
        2 => {
            3
        },
        3 => {
            4
        }
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assignment_not_last_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
        b = a;
    } else {
        a = 3;
    }
}"#,
        )
    }

    #[test]
    fn test_extract_assignment_chained_if() {
        mark::check!(test_extract_assigment_chained_if);
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else if false {
        a = 3;
    } else {
        a = 4;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        2
    } else if false {
        3
    } else {
        4
    };
}"#,
        );
    }

    #[test]
    fn test_extract_assigment_retains_stmts() {
        check_assist(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        let b = 2;
        <|>a = 2;
    } else {
        let b = 3;
        a = 3;
    }
}"#,
            r#"
fn foo() {
    let mut a = 1;

    a = if true {
        let b = 2;
        2
    } else {
        let b = 3;
        3
    };
}"#,
        )
    }

    #[test]
    fn extract_assignment_let_stmt_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    let b = if true {
        <|>a = 2
    } else {
        a = 3
    };
}"#,
        )
    }

    #[test]
    fn extract_assignment_if_missing_assigment_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    if true {
        <|>a = 2;
    } else {}
}"#,
        )
    }

    #[test]
    fn extract_assignment_match_missing_assigment_not_applicable() {
        check_assist_not_applicable(
            extract_assigment,
            r#"
fn foo() {
    let mut a = 1;

    match 1 {
        1 => {
            <|>a = 2;
        },
        2 => {
            a = 3;
        },
        3 => {},
    }
}"#,
        )
    }

    #[test]
    fn test_extract_assignment_field_assignment() {
        mark::check!(test_extract_assignment_field_assignment);
        check_assist(
            extract_assigment,
            r#"
struct A(usize);

fn foo() {
    let mut a = A(1);

    if true {
        <|>a.0 = 2;
    } else {
        a.0 = 3;
    }
}"#,
            r#"
struct A(usize);

fn foo() {
    let mut a = A(1);

    a.0 = if true {
        2
    } else {
        3
    };
}"#,
        )
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use lsp_server::{Connection, Message, Notification, Request};
use lsp_types::{
    notification::{DidOpenTextDocument, Exit},
    request::Shutdown,
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress,
};
use lsp_types::{ProgressParams, ProgressParamsValue};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use test_utils::{find_mismatch, Fixture};

use ra_project_model::ProjectManifest;
use rust_analyzer::{
    config::{ClientCapsConfig, Config, LinkedProject},
    main_loop,
};

pub struct Project<'a> {
    fixture: &'a str,
    with_sysroot: bool,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
    config: Option<Box<dyn Fn(&mut Config)>>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub(crate) fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn with_sysroot(mut self, sysroot: bool) -> Project<'a> {
        self.with_sysroot = sysroot;
        self
    }

    pub fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> {
        self.config = Some(Box::new(config));
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            env_logger::builder().is_test(true).try_init().unwrap();
            ra_prof::init_from(crate::PROFILE);
        });

        let mut paths = vec![];

        for entry in Fixture::parse(self.fixture) {
            let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let mut roots =
            self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>();
        if roots.is_empty() {
            roots.push(tmp_dir.path().to_path_buf());
        }
        let linked_projects = roots
            .into_iter()
            .map(|it| ProjectManifest::discover_single(&it).unwrap())
            .map(LinkedProject::from)
            .collect::<Vec<_>>();

        let mut config = Config {
            client_caps: ClientCapsConfig {
                location_link: true,
                code_action_literals: true,
                work_done_progress: true,
                ..Default::default()
            },
            with_sysroot: self.with_sysroot,
            linked_projects,
            ..Config::default()
        };

        if let Some(f) = &self.config {
            f(&mut config)
        }

        Server::new(tmp_dir, config, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<Message>>,
    _thread: jod_thread::JoinHandle<()>,
    client: Connection,
    /// XXX: remove the tempdir last
    dir: TempDir,
}

impl Server {
    fn new(dir: TempDir, config: Config, files: Vec<(PathBuf, String)>) -> Server {
        let (connection, client) = Connection::memory();

        let _thread = jod_thread::Builder::new()
            .name("test server".to_string())
            .spawn(move || main_loop(config, connection).unwrap())
            .expect("failed to spawn a thread");

        let res =
            Server { req_id: Cell::new(1), dir, messages: Default::default(), client, _thread };

        for (path, text) in files {
            res.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
                text_document: TextDocumentItem {
                    uri: Url::from_file_path(path).unwrap(),
                    language_id: "rust".to_string(),
                    version: 0,
                    text,
                },
            })
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: lsp_types::notification::Notification,
        N::Params: Serialize,
    {
        let r = Notification::new(N::METHOD.to_string(), params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: lsp_types::request::Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: lsp_types::request::Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = Request::new(id.into(), R::METHOD.to_string(), params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: Request) -> Value {
        let id = r.id.clone();
        self.client.sender.send(r.into()).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                Message::Request(req) if req.method == "window/workDoneProgress/create" => (),
                Message::Request(req) => panic!("unexpected request: {:?}", req),
                Message::Notification(_) => (),
                Message::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &Message| match msg {
            Message::Notification(n) if n.method == "$/progress" => {
                match n.clone().extract::<ProgressParams>("$/progress").unwrap() {
                    ProgressParams {
                        token: lsp_types::ProgressToken::String(ref token),
                        value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
                    } if token == "rustAnalyzer/roots scanned" => true,
                    _ => false,
                }
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&Message) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<Message> {
        recv_timeout(&self.client.receiver).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: Notification) {
        self.client.sender.send(Message::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.request::<Shutdown>((), Value::Null);
        self.notification::<Exit>(());
    }
}

fn recv_timeout(receiver: &Receiver<Message>) -> Option<Message> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<commit_msg>Remove useless test code<commit_after>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use lsp_server::{Connection, Message, Notification, Request};
use lsp_types::{
    notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress,
};
use lsp_types::{ProgressParams, ProgressParamsValue};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use test_utils::{find_mismatch, Fixture};

use ra_project_model::ProjectManifest;
use rust_analyzer::{
    config::{ClientCapsConfig, Config, LinkedProject},
    main_loop,
};

pub struct Project<'a> {
    fixture: &'a str,
    with_sysroot: bool,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
    config: Option<Box<dyn Fn(&mut Config)>>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub(crate) fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn with_sysroot(mut self, sysroot: bool) -> Project<'a> {
        self.with_sysroot = sysroot;
        self
    }

    pub fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> {
        self.config = Some(Box::new(config));
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            env_logger::builder().is_test(true).try_init().unwrap();
            ra_prof::init_from(crate::PROFILE);
        });

        for entry in Fixture::parse(self.fixture) {
            let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
        }

        let mut roots =
            self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>();
        if roots.is_empty() {
            roots.push(tmp_dir.path().to_path_buf());
        }
        let linked_projects = roots
            .into_iter()
            .map(|it| ProjectManifest::discover_single(&it).unwrap())
            .map(LinkedProject::from)
            .collect::<Vec<_>>();

        let mut config = Config {
            client_caps: ClientCapsConfig {
                location_link: true,
                code_action_literals: true,
                work_done_progress: true,
                ..Default::default()
            },
            with_sysroot: self.with_sysroot,
            linked_projects,
            ..Config::default()
        };

        if let Some(f) = &self.config {
            f(&mut config)
        }

        Server::new(tmp_dir, config)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<Message>>,
    _thread: jod_thread::JoinHandle<()>,
    client: Connection,
    /// XXX: remove the tempdir last
    dir: TempDir,
}

impl Server {
    fn new(dir: TempDir, config: Config) -> Server {
        let (connection, client) = Connection::memory();

        let _thread = jod_thread::Builder::new()
            .name("test server".to_string())
            .spawn(move || main_loop(config, connection).unwrap())
            .expect("failed to spawn a thread");

        Server { req_id: Cell::new(1), dir, messages: Default::default(), client, _thread }
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: lsp_types::notification::Notification,
        N::Params: Serialize,
    {
        let r = Notification::new(N::METHOD.to_string(), params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: lsp_types::request::Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: lsp_types::request::Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = Request::new(id.into(), R::METHOD.to_string(), params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: Request) -> Value {
        let id = r.id.clone();
        self.client.sender.send(r.into()).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                Message::Request(req) if req.method == "window/workDoneProgress/create" => (),
                Message::Request(req) => panic!("unexpected request: {:?}", req),
                Message::Notification(_) => (),
                Message::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &Message| match msg {
            Message::Notification(n) if n.method == "$/progress" => {
                match n.clone().extract::<ProgressParams>("$/progress").unwrap() {
                    ProgressParams {
                        token: lsp_types::ProgressToken::String(ref token),
                        value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
                    } if token == "rustAnalyzer/roots scanned" => true,
                    _ => false,
                }
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&Message) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<Message> {
        recv_timeout(&self.client.receiver).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: Notification) {
        self.client.sender.send(Message::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.request::<Shutdown>((), Value::Null);
        self.notification::<Exit>(());
    }
}

fn recv_timeout(receiver: &Receiver<Message>) -> Option<Message> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<|endoftext|>


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

///
/// Example cUrl request:
/// curl -X PUT -d '[[[{"id":"setter:talk@link.mozilla.org"}], {"String": "hello world"}]]' http://localhost:3000/api/v1/channels/set
///

use foxbox_taxonomy::adapter::*;
use foxbox_taxonomy::manager::AdapterManager;
use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::services::{ AdapterId, Id, Service, ServiceId };
use foxbox_taxonomy::util::Maybe;
use foxbox_taxonomy::values::{ format, Value };
use std::collections::HashMap;
use std::sync::Arc;

pub mod engine;
pub use self::engine::TtsEngine;

// eSpeak is the only engine supported for now.
mod espeak;
use self::espeak::EspeakEngine;

static ADAPTER_ID: &'static str = "espeak_adapter@link.mozilla.org";
static ADAPTER_NAME: &'static str = "eSpeak adapter";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

pub struct TtsAdapter<T> {
    talk_setter_id: Id<Channel>,
    engine: T
}

impl<T: TtsEngine> Adapter for TtsAdapter<T> {
    fn id(&self) -> Id<AdapterId> {
        adapter_id!(ADAPTER_ID)
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User) -> ResultMap<Id<Channel>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User) -> ResultMap<Id<Channel>, (), Error> {
        use core::ops::Deref;

        values.drain().map(|(id, value)| {
            if id == self.talk_setter_id {
                if let Value::String(text) = value {
                    self.engine.say(text.deref());
                    return (id, Ok(()));
                }
            }
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}

pub fn init(adapt: &Arc<AdapterManager>) -> Result<(), Error> {
    let engine = EspeakEngine { };
    if !engine.init() {
        warn!("eSpeak initialization failed!");
        return Err(Error::InternalError(InternalError::GenericError("eSpeak initialization failed!".to_owned())));
    }

    let talk_setter_id = Id::new("setter:talk@link.mozilla.org");
    try!(adapt.add_adapter(Arc::new(TtsAdapter {
        talk_setter_id: talk_setter_id.clone(),
        engine: engine
    })));
    let service_id = service_id!("espeak@link.mozilla.org");
    let adapter_id = adapter_id!(ADAPTER_ID);
    try!(adapt.add_service(Service::empty(&service_id, &adapter_id)));
    try!(adapt.add_channel(Channel {
        feature: Id::new("speak/sentence"),
        supports_send: Some(Signature::accepts(Maybe::Required(format::STRING.clone()))),
        id: talk_setter_id,
        service: service_id,
        adapter: adapter_id,
        .. Channel::default()
    }));
    Ok(())
}
<commit_msg>TTS: Getting rid of centralized Value<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

///
/// Example cUrl request:
/// curl -X PUT -d '[[[{"id":"setter:talk@link.mozilla.org"}], {"String": "hello world"}]]' http://localhost:3000/api/v1/channels/set
///

use foxbox_taxonomy::adapter::*;
use foxbox_taxonomy::manager::AdapterManager;
use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::services::{ AdapterId, Id, Service, ServiceId };
use foxbox_taxonomy::util::Maybe;
use foxbox_taxonomy::values::{ format, Value };
use std::collections::HashMap;
use std::sync::Arc;

pub mod engine;
pub use self::engine::TtsEngine;

// eSpeak is the only engine supported for now.
mod espeak;
use self::espeak::EspeakEngine;

static ADAPTER_ID: &'static str = "espeak_adapter@link.mozilla.org";
static ADAPTER_NAME: &'static str = "eSpeak adapter";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

pub struct TtsAdapter<T> {
    talk_setter_id: Id<Channel>,
    engine: T
}

impl<T: TtsEngine> Adapter for TtsAdapter<T> {
    fn id(&self) -> Id<AdapterId> {
        adapter_id!(ADAPTER_ID)
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User) -> ResultMap<Id<Channel>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User) -> ResultMap<Id<Channel>, (), Error> {
        use core::ops::Deref;

        values.drain().map(|(id, value)| {
            if id == self.talk_setter_id {
                match value.cast::<String>() {
                    Ok(text) => {
                        self.engine.say(text.deref());
                        return (id, Ok(()));
                    }
                    Err(err) => {
                        return (id, Err(err))
                    }
                }
            }
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}

pub fn init(adapt: &Arc<AdapterManager>) -> Result<(), Error> {
    let engine = EspeakEngine { };
    if !engine.init() {
        warn!("eSpeak initialization failed!");
        return Err(Error::InternalError(InternalError::GenericError("eSpeak initialization failed!".to_owned())));
    }

    let talk_setter_id = Id::new("setter:talk@link.mozilla.org");
    try!(adapt.add_adapter(Arc::new(TtsAdapter {
        talk_setter_id: talk_setter_id.clone(),
        engine: engine
    })));
    let service_id = service_id!("espeak@link.mozilla.org");
    let adapter_id = adapter_id!(ADAPTER_ID);
    try!(adapt.add_service(Service::empty(&service_id, &adapter_id)));
    try!(adapt.add_channel(Channel {
        feature: Id::new("speak/sentence"),
        supports_send: Some(Signature::accepts(Maybe::Required(format::STRING.clone()))),
        id: talk_setter_id,
        service: service_id,
        adapter: adapter_id,
        .. Channel::default()
    }));
    Ok(())
}
<|endoftext|>