<commit_before>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel;
use diesel::pg::{Pg, PgConnection};
use diesel::pg::upsert::*;
use diesel::prelude::*;
use semver;
use serde_json;
use time::{Duration, Timespec, now_utc, strptime};
use url;

use Crate;
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use owner::{rights, Rights};
use schema::*;
use user::RequestUser;
use util::errors::CargoError;
use util::{RequestUtils, CargoResult, human};
use license_exprs;

// This is necessary to allow joining version to both crates and readme_rendering
// in the render-readmes script.
enable_multi_table_joins!(crates, readme_rendering);

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: String,
    license: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersion {
    pub id: i32,
    #[serde(rename = "crate")]
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub readme_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
    pub links: VersionLinks,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

#[derive(Insertable, Identifiable, Queryable, Associations, Debug, Clone, Copy)]
#[belongs_to(Version)]
#[table_name = "readme_rendering"]
#[primary_key(version_id)]
struct ReadmeRendering {
    version_id: i32,
    rendered_at: Timespec,
}

impl Version {
    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            license: license,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn max<T>(versions: T) -> semver::Version
    where
        T: IntoIterator<Item = semver::Version>,
    {
        versions.into_iter().max().unwrap_or_else(|| {
            semver::Version {
                major: 0,
                minor: 0,
                patch: 0,
                pre: vec![],
                build: vec![],
            }
        })
    }

    pub fn record_readme_rendering(&self, conn: &PgConnection) -> CargoResult<()> {
        let rendered = ReadmeRendering {
            version_id: self.id,
            rendered_at: ::now(),
        };

        diesel::insert(&rendered.on_conflict(
            readme_rendering::version_id,
            do_update().set(
                (readme_rendering::rendered_at.eq(
                    excluded(
                        readme_rendering::rendered_at,
                    ),
                )),
            ),
        )).into(readme_rendering::table)
            .execute(&*conn)?;
        Ok(())
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
    ) -> CargoResult<Self> {
        let features = serde_json::to_string(features)?;

        let mut new_version = NewVersion {
            crate_id: crate_id,
            num: num.to_string(),
            features: features,
            license: license,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult<Version> {
        use diesel::{select, insert};
        use diesel::expression::dsl::exists;
        use schema::versions::dsl::*;

        let already_uploaded = versions.filter(crate_id.eq(self.crate_id)).filter(
            num.eq(&self.num),
        );
        if select(exists(already_uploaded)).get_result(conn)? {
            return Err(human(&format_args!(
                "crate version `{}` is already \
                 uploaded",
                self.num
            )));
        }

        conn.transaction(|| {
            let version = insert(self).into(versions).get_result::<Version>(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| {
                    NewAuthor {
                        version_id: version.id,
                        name: &*s,
                    }
                })
                .collect::<Vec<_>>();

            insert(&new_authors).into(version_authors::table).execute(
                conn,
            )?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    human(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

#[derive(Insertable, Debug)]
#[table_name = "version_authors"]
struct NewAuthor<'a> {
    version_id: i32,
    name: &'a str,
}

impl Queryable<versions::SqlType, Pg> for Version {
    type Row = (i32, i32, String, Timespec, Timespec, i32, Option<String>, bool, Option<String>);

    fn build(row: Self::Row) -> Self {
        let features = row.6
            .map(|s| serde_json::from_str(&s).unwrap())
            .unwrap_or_else(HashMap::new);
        Version {
            id: row.0,
            crate_id: row.1,
            num: semver::Version::parse(&row.2).unwrap(),
            updated_at: row.3,
            created_at: row.4,
            downloads: row.5,
            features: features,
            yanked: row.7,
            license: row.8,
        }
    }
}

/// Handles the `GET /versions` route.
// FIXME: where/how is this used?
pub fn index(req: &mut Request) -> CargoResult<Response> {
    use diesel::expression::dsl::any;
    let conn = req.db_conn()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("").as_bytes());
    let ids = query
        .filter_map(|(ref a, ref b)| if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        })
        .collect::<Vec<i32>>();

    let versions = versions::table
        .inner_join(crates::table)
        .select((versions::all_columns, crates::name))
        .filter(versions::id.eq(any(ids)))
        .load::<(Version, String)>(&*conn)?
        .into_iter()
        .map(|(version, crate_name)| version.encodable(&crate_name))
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
    }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.db_conn()?;
            versions::table
                .find(id)
                .inner_join(crates::table)
                .select((versions::all_columns, ::krate::ALL_COLUMNS))
                .first(&*conn)?
        }
    };

    #[derive(Serialize)]
    struct R {
        version: EncodableVersion,
    }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    if semver::Version::parse(semver).is_err() {
        return Err(human(&format_args!("invalid semver: {}", semver)));
    };
    let conn = req.db_conn()?;
    let krate = Crate::by_name(crate_name).first::<Crate>(&*conn)?;
    let version = Version::belonging_to(&krate)
        .filter(versions::num.eq(semver))
        .first(&*conn)
        .map_err(|_| {
            human(&format_args!(
                "crate `{}` does not have a version `{}`",
                crate_name,
                semver
            ))
        })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let deps = version.dependencies(&*conn)?;
    let deps = deps.into_iter()
        .map(|(dep, crate_name)| dep.encodable(&crate_name, None))
        .collect();

    #[derive(Serialize)]
    struct R {
        dependencies: Vec<EncodableDependency>,
    }
    Ok(req.json(&R { dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    use diesel::expression::dsl::date;
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let cutoff_end_date = req.query()
        .get("before_date")
        .and_then(|d| strptime(d, "%Y-%m-%d").ok())
        .unwrap_or_else(now_utc)
        .to_timespec();
    let cutoff_start_date = cutoff_end_date + Duration::days(-89);

    let downloads = VersionDownload::belonging_to(&version)
        .filter(version_downloads::date.between(
            date(cutoff_start_date)..
                date(cutoff_end_date),
        ))
        .order(version_downloads::date)
        .load(&*conn)?
        .into_iter()
        .map(VersionDownload::encodable)
        .collect();

    #[derive(Serialize)]
    struct R {
        version_downloads: Vec<EncodableVersionDownload>,
    }
    Ok(req.json(&R { version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let names = version_authors::table
        .filter(version_authors::version_id.eq(version.id))
        .select(version_authors::name)
        .order(version_authors::name)
        .load(&*conn)?;

    // It was imagined that we wold associate authors with users.
    // This was never implemented. This complicated return struct
    // is all that is left, hear for backwards compatibility.
    #[derive(Serialize)]
    struct R {
        users: Vec<::user::EncodablePublicUser>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        names: Vec<String>,
    }
    Ok(req.json(&R {
        users: vec![],
        meta: Meta { names: names },
    }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
/// This does not delete a crate version, it makes the crate
/// version accessible only to crates that already have a
/// `Cargo.lock` containing this version.
///
/// Notes:
/// Crate deletion is not implemented to avoid breaking builds,
/// and the goal of yanking a crate is to prevent crates
/// beginning to depend on the yanked crate version.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

/// Changes `yanked` flag on a crate version record
fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let conn = req.db_conn()?;
    let owners = krate.owners(&conn)?;
    if rights(req.app(), &owners, user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"));
    }

    if version.yanked != yanked {
        conn.transaction::<_, Box<CargoError>, _>(|| {
            diesel::update(&version)
                .set(versions::yanked.eq(yanked))
                .execute(&*conn)?;
            git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
            Ok(())
        })?;
    }

    #[derive(Serialize)]
    struct R {
        ok: bool,
    }
    Ok(req.json(&R { ok: true }))
}
<commit_msg>Remove unnecessary parens<commit_after>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel;
use diesel::pg::{Pg, PgConnection};
use diesel::pg::upsert::*;
use diesel::prelude::*;
use semver;
use serde_json;
use time::{Duration, Timespec, now_utc, strptime};
use url;

use Crate;
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use owner::{rights, Rights};
use schema::*;
use user::RequestUser;
use util::errors::CargoError;
use util::{RequestUtils, CargoResult, human};
use license_exprs;

// This is necessary to allow joining version to both crates and readme_rendering
// in the render-readmes script.
enable_multi_table_joins!(crates, readme_rendering);

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: String,
    license: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersion {
    pub id: i32,
    #[serde(rename = "crate")]
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub readme_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
    pub links: VersionLinks,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

#[derive(Insertable, Identifiable, Queryable, Associations, Debug, Clone, Copy)]
#[belongs_to(Version)]
#[table_name = "readme_rendering"]
#[primary_key(version_id)]
struct ReadmeRendering {
    version_id: i32,
    rendered_at: Timespec,
}

impl Version {
    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            license: license,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn max<T>(versions: T) -> semver::Version
    where
        T: IntoIterator<Item = semver::Version>,
    {
        versions.into_iter().max().unwrap_or_else(|| {
            semver::Version {
                major: 0,
                minor: 0,
                patch: 0,
                pre: vec![],
                build: vec![],
            }
        })
    }

    pub fn record_readme_rendering(&self, conn: &PgConnection) -> CargoResult<()> {
        let rendered = ReadmeRendering {
            version_id: self.id,
            rendered_at: ::now(),
        };

        diesel::insert(&rendered.on_conflict(
            readme_rendering::version_id,
            do_update().set(
                readme_rendering::rendered_at.eq(
                    excluded(
                        readme_rendering::rendered_at,
                    ),
                ),
            ),
        )).into(readme_rendering::table)
            .execute(&*conn)?;
        Ok(())
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
    ) -> CargoResult<Self> {
        let features = serde_json::to_string(features)?;

        let mut new_version = NewVersion {
            crate_id: crate_id,
            num: num.to_string(),
            features: features,
            license: license,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult<Version> {
        use diesel::{select, insert};
        use diesel::expression::dsl::exists;
        use schema::versions::dsl::*;

        let already_uploaded = versions.filter(crate_id.eq(self.crate_id)).filter(
            num.eq(&self.num),
        );
        if select(exists(already_uploaded)).get_result(conn)? {
            return Err(human(&format_args!(
                "crate version `{}` is already \
                 uploaded",
                self.num
            )));
        }

        conn.transaction(|| {
            let version = insert(self).into(versions).get_result::<Version>(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| {
                    NewAuthor {
                        version_id: version.id,
                        name: &*s,
                    }
                })
                .collect::<Vec<_>>();

            insert(&new_authors).into(version_authors::table).execute(
                conn,
            )?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    human(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

#[derive(Insertable, Debug)]
#[table_name = "version_authors"]
struct NewAuthor<'a> {
    version_id: i32,
    name: &'a str,
}

impl Queryable<versions::SqlType, Pg> for Version {
    type Row = (i32, i32, String, Timespec, Timespec, i32, Option<String>, bool, Option<String>);

    fn build(row: Self::Row) -> Self {
        let features = row.6
            .map(|s| serde_json::from_str(&s).unwrap())
            .unwrap_or_else(HashMap::new);
        Version {
            id: row.0,
            crate_id: row.1,
            num: semver::Version::parse(&row.2).unwrap(),
            updated_at: row.3,
            created_at: row.4,
            downloads: row.5,
            features: features,
            yanked: row.7,
            license: row.8,
        }
    }
}

/// Handles the `GET /versions` route.
// FIXME: where/how is this used?
pub fn index(req: &mut Request) -> CargoResult<Response> {
    use diesel::expression::dsl::any;
    let conn = req.db_conn()?;

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("").as_bytes());
    let ids = query
        .filter_map(|(ref a, ref b)| if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        })
        .collect::<Vec<i32>>();

    let versions = versions::table
        .inner_join(crates::table)
        .select((versions::all_columns, crates::name))
        .filter(versions::id.eq(any(ids)))
        .load::<(Version, String)>(&*conn)?
        .into_iter()
        .map(|(version, crate_name)| version.encodable(&crate_name))
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
    }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => version_and_crate(req)?,
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = req.db_conn()?;
            versions::table
                .find(id)
                .inner_join(crates::table)
                .select((versions::all_columns, ::krate::ALL_COLUMNS))
                .first(&*conn)?
        }
    };

    #[derive(Serialize)]
    struct R {
        version: EncodableVersion,
    }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    if semver::Version::parse(semver).is_err() {
        return Err(human(&format_args!("invalid semver: {}", semver)));
    };
    let conn = req.db_conn()?;
    let krate = Crate::by_name(crate_name).first::<Crate>(&*conn)?;
    let version = Version::belonging_to(&krate)
        .filter(versions::num.eq(semver))
        .first(&*conn)
        .map_err(|_| {
            human(&format_args!(
                "crate `{}` does not have a version `{}`",
                crate_name,
                semver
            ))
        })?;
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let deps = version.dependencies(&*conn)?;
    let deps = deps.into_iter()
        .map(|(dep, crate_name)| dep.encodable(&crate_name, None))
        .collect();

    #[derive(Serialize)]
    struct R {
        dependencies: Vec<EncodableDependency>,
    }
    Ok(req.json(&R { dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    use diesel::expression::dsl::date;
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let cutoff_end_date = req.query()
        .get("before_date")
        .and_then(|d| strptime(d, "%Y-%m-%d").ok())
        .unwrap_or_else(now_utc)
        .to_timespec();
    let cutoff_start_date = cutoff_end_date + Duration::days(-89);

    let downloads = VersionDownload::belonging_to(&version)
        .filter(version_downloads::date.between(
            date(cutoff_start_date)..
                date(cutoff_end_date),
        ))
        .order(version_downloads::date)
        .load(&*conn)?
        .into_iter()
        .map(VersionDownload::encodable)
        .collect();

    #[derive(Serialize)]
    struct R {
        version_downloads: Vec<EncodableVersionDownload>,
    }
    Ok(req.json(&R { version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let names = version_authors::table
        .filter(version_authors::version_id.eq(version.id))
        .select(version_authors::name)
        .order(version_authors::name)
        .load(&*conn)?;

    // It was imagined that we wold associate authors with users.
    // This was never implemented. This complicated return struct
    // is all that is left, hear for backwards compatibility.
    #[derive(Serialize)]
    struct R {
        users: Vec<::user::EncodablePublicUser>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        names: Vec<String>,
    }
    Ok(req.json(&R {
        users: vec![],
        meta: Meta { names: names },
    }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
/// This does not delete a crate version, it makes the crate
/// version accessible only to crates that already have a
/// `Cargo.lock` containing this version.
///
/// Notes:
/// Crate deletion is not implemented to avoid breaking builds,
/// and the goal of yanking a crate is to prevent crates
/// beginning to depend on the yanked crate version.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

/// Changes `yanked` flag on a crate version record
fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = version_and_crate(req)?;
    let user = req.user()?;
    let conn = req.db_conn()?;
    let owners = krate.owners(&conn)?;
    if rights(req.app(), &owners, user)? < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"));
    }

    if version.yanked != yanked {
        conn.transaction::<_, Box<CargoError>, _>(|| {
            diesel::update(&version)
                .set(versions::yanked.eq(yanked))
                .execute(&*conn)?;
            git::yank(&**req.app(), &krate.name, &version.num, yanked)?;
            Ok(())
        })?;
    }

    #[derive(Serialize)]
    struct R {
        ok: bool,
    }
    Ok(req.json(&R { ok: true }))
}
<|endoftext|>


<commit_before>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use engine::EngineData;
use text_renderer::TextRenderer;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::surface::Surface;
use std::io::Result;
use std::path::Path;
use uorustlibs::art::{ArtReader, Art};
use uorustlibs::hues::{HueReader, HueGroup, Hue};
use uorustlibs::color::{Color16, Color as ColorTrait};
use uorustlibs::map::{MapReader, Block, RadarColReader};

use std::io::{Error, };
use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

const MAX_BLOCKS_WIDTH: usize = 1024 / 8;
const MAX_BLOCKS_HEIGHT: usize = 768 / 8;
const STEP_X: usize = MAX_BLOCKS_WIDTH / 4;
const STEP_Y: usize = MAX_BLOCKS_HEIGHT / 4;

enum MapRenderMode {
    HeightMap,
    RadarMap,
}

pub struct MapScene {
    map_reader: Result<MapReader>,
    radar_colors: Result<Vec<Color16>>,
    x: u32,
    y: u32,
    mode: MapRenderMode,
    texture: Option<Texture>
}

pub fn draw_heightmap_block<'a>(block: &Block, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        let mut read_idx = 0;

        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let height = (block.cells[target].altitude as i16 + 128) as u8;
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = height;
                bitmap[target * 4 + 2] = height;
                bitmap[target * 4 + 3] = height;
            }
        };
    });
    surface
}

pub fn draw_radarcol_block<'a>(block: &Block, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        let mut read_idx = 0;

        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let index = block.cells[target].graphic;
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[index as usize].to_rgba(),
                    _ => index.to_rgba()
                };
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = b;
                bitmap[target * 4 + 2] = g;
                bitmap[target * 4 + 3] = r;
            }
        };
    });
    surface
}

impl MapScene {
    pub fn new<'a>(renderer: &mut Renderer, engine_data: &mut EngineData<'a>) -> BoxedScene<SceneName, EngineData<'a>> {
        let colors = RadarColReader::new(&Path::new("./assets/radarcol.mul"))
            .and_then(|mut reader| reader.read_colors());

        let mut scene = Box::new(MapScene {
            map_reader: MapReader::new(&Path::new("./assets/map0.mul"), 768, 512),
            x: 0,
            y: 0,
            texture: None,
            mode: MapRenderMode::HeightMap,
            radar_colors: colors
        });
        scene.draw_page(renderer, engine_data);
        scene
    }

    pub fn get_blocks(&mut self) -> Vec<Result<Block>> {
        let mut blocks = vec![];

        match self.map_reader {
            Ok(ref mut map_reader) => {
                for y in 0..MAX_BLOCKS_HEIGHT {
                    for x in 0..MAX_BLOCKS_WIDTH {
                        let block = map_reader.read_block_from_coordinates(self.x + x as u32, self.y + y as u32);
                        blocks.push(block);
                    }
                }
            },
            _ => ()
        };
        blocks
    }

    pub fn draw_page(&mut self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        let blocks = self.get_blocks();
        let block_drawer = match self.mode {
            MapRenderMode::HeightMap => draw_heightmap_block,
            MapRenderMode::RadarMap => draw_radarcol_block,
        };
        let mut surface = Surface::new(1024, 768, PixelFormatEnum::RGBA8888).unwrap();
        for y in 0..MAX_BLOCKS_HEIGHT {
            for x in 0..MAX_BLOCKS_WIDTH {
                match blocks[x + (y * MAX_BLOCKS_WIDTH)] {
                    Ok(ref block) => {
                        let block_surface = block_drawer(block, &self.radar_colors);
                        block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                    },
                    _ => ()
                }
            }
        }
        self.texture = Some(renderer.create_texture_from_surface(&surface).unwrap())
    }
}

impl<'a> Scene<SceneName, EngineData<'a>> for MapScene {
    fn render(&self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        renderer.clear();
        match self.texture {
            Some(ref texture) => {
                renderer.copy(texture, None, None).unwrap();
            },
            None => ()
        };
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, renderer: &mut Renderer, engine_data: &mut EngineData) -> Option<SceneChangeEvent<SceneName>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.x >= STEP_X as u32 {
                    self.x -= STEP_X as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.x += STEP_X as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.y >= STEP_Y as u32 {
                    self.y -= STEP_Y as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.y += STEP_Y as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
                self.mode = MapRenderMode::RadarMap;
                self.draw_page(renderer, engine_data);
                None
            },
             _ => None
        }
    }
}
<commit_msg>Moving towards partial updating of maps<commit_after>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use engine::EngineData;
use text_renderer::TextRenderer;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::surface::Surface;
use std::io::Result;
use std::path::Path;
use uorustlibs::art::{ArtReader, Art};
use uorustlibs::hues::{HueReader, HueGroup, Hue};
use uorustlibs::color::{Color16, Color as ColorTrait};
use uorustlibs::map::{MapReader, Block, RadarColReader};

use std::io::{Error, };
use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

const MAX_BLOCKS_WIDTH: u32 = 1024 / 8;
const MAX_BLOCKS_HEIGHT: u32 = 768 / 8;
const STEP_X: u32 = MAX_BLOCKS_WIDTH / 4;
const STEP_Y: u32 = MAX_BLOCKS_HEIGHT / 4;

struct MapLens {
    pub blocks: Vec<Option<Block>>,
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl MapLens {
    pub fn new(map_reader: &mut MapReader, x: u32, y: u32, width: u32, height: u32) -> MapLens {
        let mut blocks = vec![];
        for yy in 0..height {
            for xx in 0..width {
                let block = map_reader.read_block_from_coordinates(x + xx, y + yy);
                blocks.push(block.ok());
            }
        }
        MapLens {
            blocks: blocks,
            x: x,
            y: y,
            width: width,
            height: height
        }
    }

    pub fn update(&self, map_reader: &mut MapReader, x: u32, y: u32) -> MapLens {
        let difference_x = x as i64 - self.x as i64;
        let difference_y = y as i64 - self.y as i64;
        println!("{} {}", difference_x, difference_y);
        MapLens {
            blocks: self.blocks.clone(),
            x: x,
            y: y,
            width: self.width,
            height: self.height
        }
    }
}

enum MapRenderMode {
    HeightMap,
    RadarMap,
}

pub struct MapScene {
    map_reader: Result<MapReader>,
    radar_colors: Result<Vec<Color16>>,
    x: u32,
    y: u32,
    mode: MapRenderMode,
    texture: Option<Texture>,
    map_lens: Option<MapLens>
}

pub fn draw_heightmap_block<'a>(block: &Block, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        let mut read_idx = 0;

        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let height = (block.cells[target].altitude as i16 + 128) as u8;
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = height;
                bitmap[target * 4 + 2] = height;
                bitmap[target * 4 + 3] = height;
            }
        };
    });
    surface
}

pub fn draw_radarcol_block<'a>(block: &Block, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        let mut read_idx = 0;

        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let index = block.cells[target].graphic;
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[index as usize].to_rgba(),
                    _ => index.to_rgba()
                };
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = b;
                bitmap[target * 4 + 2] = g;
                bitmap[target * 4 + 3] = r;
            }
        };
    });
    surface
}

impl MapScene {
    pub fn new<'a>(renderer: &mut Renderer, engine_data: &mut EngineData<'a>) -> BoxedScene<SceneName, EngineData<'a>> {
        let colors = RadarColReader::new(&Path::new("./assets/radarcol.mul"))
            .and_then(|mut reader| reader.read_colors());

        let mut scene = Box::new(MapScene {
            map_reader: MapReader::new(&Path::new("./assets/map0.mul"), 768, 512),
            x: 0,
            y: 0,
            texture: None,
            mode: MapRenderMode::HeightMap,
            radar_colors: colors,
            map_lens: None
        });

        scene.draw_page(renderer, engine_data);
        scene
    }

    pub fn refresh_lens(&mut self) {
        let map_lens = match (&mut self.map_lens, &mut self.map_reader) {
            (&mut Some(ref lens), &mut Ok(ref mut map_reader)) => {
                Some(lens.update(map_reader, self.x, self.y))
            },
            (&mut None, &mut Ok(ref mut map_reader)) => {
                Some(MapLens::new(map_reader, self.x, self.y, MAX_BLOCKS_WIDTH, MAX_BLOCKS_HEIGHT))
            },
            _ => None
        };
        self.map_lens = map_lens;
    }

    pub fn draw_page(&mut self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        self.refresh_lens();

        self.texture = match self.map_lens {
            Some(ref lens) => {
                let mut surface = Surface::new(1024, 768, PixelFormatEnum::RGBA8888).unwrap();
                let block_drawer = match self.mode {
                    MapRenderMode::HeightMap => draw_heightmap_block,
                    MapRenderMode::RadarMap => draw_radarcol_block,
                };
                for y in 0..lens.height {
                    for x in 0..lens.width {
                        match lens.blocks[(x + (y * MAX_BLOCKS_WIDTH)) as usize] {
                            Some(ref block) => {
                                let block_surface = block_drawer(block, &self.radar_colors);
                                block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                            },
                            _ => ()
                        }
                    }
                }
                Some(renderer.create_texture_from_surface(&surface).unwrap())
            },
            None => None
        }
    }
}

impl<'a> Scene<SceneName, EngineData<'a>> for MapScene {
    fn render(&self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        renderer.clear();
        match self.texture {
            Some(ref texture) => {
                renderer.copy(texture, None, None).unwrap();
            },
            None => ()
        };
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, renderer: &mut Renderer, engine_data: &mut EngineData) -> Option<SceneChangeEvent<SceneName>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.x >= STEP_X as u32 {
                    self.x -= STEP_X as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.x += STEP_X as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.y >= STEP_Y as u32 {
                    self.y -= STEP_Y as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.y += STEP_Y as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
                self.mode = MapRenderMode::RadarMap;
                self.draw_page(renderer, engine_data);
                None
            },
             _ => None
        }
    }
}
<|endoftext|>


<commit_before>use super::common::Context;
use super::ast::*;
use super::tokens::{Number, Boolean, NodeImpl, Node, Operator};
use super::types::{Type, TypeTable};
use super::scope::ScopedTable;
use super::ident::Identifier;
use super::functions::{self, FunctionTable};

use llvm;
use llvm::{Compile, ExecutionEngine, CastFrom};
use cbox::*;
use std::cell::{RefCell, RefMut};

const GLOBAL_INIT_FN_NAME: &'static str = "__global_init";

pub fn codegen<'a>(ctxt: &'a Context<'a>) {
    CodeGenerator::new(ctxt).codegen();
}

struct CodeGenerator<'a> {
    ctxt: &'a Context<'a>,
    types: RefMut<'a, TypeTable>,
    functions: RefMut<'a, FunctionTable>,
    llvm: &'a llvm::Context,
    module: CSemiBox<'a, llvm::Module>,
    builder: CSemiBox<'a, llvm::Builder>,
    values: RefCell<ScopedTable<*const llvm::Value>>,
}

impl<'a> CodeGenerator<'a> {
    fn new(ctxt: &'a Context<'a>) -> CodeGenerator<'a> {
        CodeGenerator {
            ctxt: ctxt,
            types: ctxt.types.borrow_mut(),
            functions: ctxt.functions.borrow_mut(),
            llvm: &ctxt.llvm,
            module: llvm::Module::new(&ctxt.filename, &ctxt.llvm),
            builder: llvm::Builder::new(&ctxt.llvm),
            values: RefCell::new(ScopedTable::new()),
        }
    }

    fn codegen(&self) {
        self.codegen_root(&self.ctxt.ast.borrow());

        println!("{:?}", self.module);
        self.module.verify().unwrap();

        {
            let init = self.module.get_function(GLOBAL_INIT_FN_NAME).unwrap();
            let ee = llvm::JitEngine::new(&self.module, llvm::JitOptions { opt_level: 0 }).unwrap();
            //let ee = llvm::Interpreter::new(&self.module, ()).unwrap();
            ee.with_function(init, |init: extern fn(())| {
                init(());
            });
        }
    }

    fn codegen_root(&self, root: &Root) {
        let unit_ty = llvm::Type::get::<()>(self.llvm);
        let init_fn = self.module.add_function(GLOBAL_INIT_FN_NAME,
                                               llvm::Type::new_function(unit_ty, &[]));
        let mut block = init_fn.append("entry");
        self.builder.position_at_end(block);

        for item in root {
            match *item {
                Item::Assignment(ref x) => {
                    self.builder.position_at_end(block);
                    self.codegen_global_assignment(x, init_fn);
                    block = self.builder.get_position();
                },
                Item::FunctionDef(ref x) => {
                    self.codegen_global_function(x);
                }
            }
        }

        self.builder.build_ret_void();
    }

    fn codegen_global_function(&self, func: &FunctionDef) {
        let ident = func.ident();
        if !self.functions.get(ident).unwrap().has_concrete_type() {
            return; // in other words, the function was never used, so the type of it's signature is unknown
        }
        let name = self.ctxt.lookup_name(ident);
        let ty = self.type_to_llvm(self.types.get_symbol(ident).unwrap().val);
        let num_args = func.args().len();
        println!("TYPE {:?}", ty);
        let llvm_func = self.module.add_function(&name, ty);
        self.values.borrow_mut().set_val(ident, func.ident_pos().index,
                                         llvm_func as *const llvm::Function as *const llvm::Value);
        let entry = llvm_func.append("entry");
        self.builder.position_at_end(entry);
        self.values.borrow_mut().push(func.ident_pos().index);
        for i in 0..num_args {
            let ref arg = func.args()[i];
            &llvm_func[i].set_name(&self.ctxt.lookup_name(arg.ident().unwrap()));
            self.values.borrow_mut().set_val(arg.ident().unwrap(), arg.pos().index,
                                             &llvm_func[i] as *const llvm::Arg as *const llvm::Value);
        }
        let res = self.codegen_block(&func.block, llvm_func);
        self.builder.build_ret(res);
        self.values.borrow_mut().pop();
    }

    fn codegen_global_assignment(&self, assign: &Assignment, func: &llvm::Function) {
        let synt_ty = self.types.get_symbol(assign.ident()).unwrap().val;
        let ty = self.type_to_llvm(synt_ty);
        let name = &self.ctxt.lookup_name(assign.ident());
        let global = self.module.add_global(name, ty);
        global.set_initializer(llvm::Value::new_undef(ty));
        let val = self.codegen_expr(assign.expr(), func);
        self.builder.build_store(val, global);

        // hopefully there's some way to make this not use raw pointers.
        self.values.borrow_mut().set_val(assign.ident(), assign.ident_pos().index,
                                         global as *const llvm::GlobalValue as *const llvm::Value);
    }

    fn codegen_assignment(&self, assign: &Assignment, func: &llvm::Function) {
        let name = &self.ctxt.lookup_name(assign.ident());
        let val = self.codegen_expr(assign.expr(), func);
        val.set_name(name);

        // hopefully there's some way to make this not use raw pointers.
        self.values.borrow_mut().set_val(assign.ident(), assign.ident_pos().index,
                                         val as *const llvm::Value);
    }

    fn codegen_expr(&self, expr: &Expression, func: &llvm::Function) -> &llvm::Value {
        match *expr {
            Expression::Constant(Node(v, _)) => v.compile(self.llvm),
            Expression::Boolean(Node(v, _)) => v.compile(self.llvm),
            Expression::Infix(ref v) => self.codegen_infix(v, func),
            Expression::Prefix(ref v) => self.codegen_prefix(v, func),
            Expression::Variable(ref v) => self.codegen_var(**v, func),
            Expression::Conditional(ref v) => self.codegen_conditional(v, func),
            Expression::Block(ref v) => self.codegen_block(v, func),
            _ => unimplemented!(),
        }
    }

    fn codegen_block(&self, block: &Node<Block>, func: &llvm::Function) -> &llvm::Value {
        self.values.borrow_mut().push(block.pos().index);
        let mut value = None;
        for stmnt in block.item() {
            match *stmnt {
                Statement::Assignment(ref v) => {
                    self.codegen_assignment(v, func);
                },
                Statement::Expression(ref v) => {
                    let expr = self.codegen_expr(v, func);
                    if expr.get_type().is_float() {
                        value = match value {
                            None => Some(expr),
                            Some(v) => Some(self.builder.build_add(v, expr)),
                        };
                    } else {
                        value = Some(expr);
                    }
                },
            }
        }
        self.values.borrow_mut().pop();
        value.unwrap()
    }

    fn codegen_var(&self, ident: Identifier, _: &llvm::Function) -> &llvm::Value {
        let values = self.values.borrow();
        let sym = values.get_symbol(ident).unwrap();
        let value = unsafe { &*sym.val };
        if llvm::GlobalValue::cast(value).is_some() {
            self.builder.build_load(value)
        } else {
            value
        }
    }

    fn codegen_conditional(&self, cond: &Conditional, func: &llvm::Function) -> &llvm::Value {
        let cond_val = self.codegen_expr(cond.cond(), func);
        let then_block = func.append("then");
        let else_block = func.append("else");
        self.builder.build_cond_br(cond_val, then_block, Some(else_block));

        let merge_block = func.append("merge");

        self.builder.position_at_end(then_block);
        let then_val = self.codegen_expr(cond.then(), func);
        self.builder.build_br(merge_block);
        let then_block = self.builder.get_position();

        self.builder.position_at_end(else_block);
        let else_val = self.codegen_expr(cond.els(), func);
        self.builder.build_br(merge_block);
        let else_block = self.builder.get_position();

        self.builder.position_at_end(merge_block);
        assert!(then_val.get_type() == else_val.get_type());
        let phi = self.builder.build_phi(then_val.get_type(), "iftmp");
        phi.add_incoming(then_val, then_block);
        phi.add_incoming(else_val, else_block);
        phi
    }

    fn codegen_infix(&self, infix: &Infix, func: &llvm::Function) -> &llvm::Value {
        let lhs = self.codegen_expr(infix.left(), func);
        let rhs = self.codegen_expr(infix.right(), func);
        match infix.op() {
            Operator::Add => self.builder.build_add(lhs, rhs),
            Operator::Sub => self.builder.build_sub(lhs, rhs),
            Operator::Mul => self.builder.build_mul(lhs, rhs),
            Operator::Div => self.builder.build_div(lhs, rhs),
            Operator::Less => self.builder.build_cmp(lhs, rhs, llvm::Predicate::LessThan),
            Operator::Greater => self.builder.build_cmp(lhs, rhs, llvm::Predicate::GreaterThan),
            Operator::LessEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::LessThanOrEqual),
            Operator::GreaterEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::GreaterThanOrEqual),
            Operator::Equal => self.builder.build_cmp(lhs, rhs, llvm::Predicate::Equal),
            Operator::NotEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::NotEqual),
            Operator::Or => self.builder.build_or(lhs, rhs),
            Operator::And => self.builder.build_and(lhs, rhs),
            Operator::Xor => self.builder.build_xor(lhs, rhs),
            _ => unreachable!(),
        }
    }

    fn codegen_prefix(&self, prefix: &Prefix, func: &llvm::Function) -> &llvm::Value {
        let expr = self.codegen_expr(prefix.expr(), func);
        match prefix.op() {
            Operator::Sub => self.builder.build_sub(0f32.compile(self.llvm), expr),
            Operator::Not => self.builder.build_not(expr),
            _ => unreachable!(),
        }
    }

    fn type_to_llvm(&self, ty: Type) -> &llvm::Type {
        match ty {
            Type::Number => llvm::Type::get::<Number>(self.llvm),
            Type::Boolean => llvm::Type::get::<Boolean>(self.llvm),
            Type::Function(id) => {
                let func = self.functions.get(id).unwrap();
                let ty = match *func {
                    functions::Function::User(ref f) => f.ty.as_ref().unwrap(),
                    functions::Function::Builtin(ref f) => &f.ty,
                };
                let args: Vec<&llvm::Type> = ty.args.iter().map(|(_, &ty)| self.type_to_llvm(ty)).collect();
                let ret = self.type_to_llvm(ty.returns);
                llvm::Type::new_function(ret, &args)
            }
            _ => unreachable!(),
        }
    }
}

<commit_msg>Remove unnecessary mutability<commit_after>use super::common::Context;
use super::ast::*;
use super::tokens::{Number, Boolean, NodeImpl, Node, Operator};
use super::types::{Type, TypeTable};
use super::scope::ScopedTable;
use super::ident::Identifier;
use super::functions::{self, FunctionTable};

use llvm;
use llvm::{Compile, ExecutionEngine, CastFrom};
use cbox::*;
use std::cell::{RefCell, Ref};

const GLOBAL_INIT_FN_NAME: &'static str = "__global_init";

pub fn codegen<'a>(ctxt: &'a Context<'a>) {
    CodeGenerator::new(ctxt).codegen();
}

struct CodeGenerator<'a> {
    ctxt: &'a Context<'a>,
    types: Ref<'a, TypeTable>,
    functions: Ref<'a, FunctionTable>,
    llvm: &'a llvm::Context,
    module: CSemiBox<'a, llvm::Module>,
    builder: CSemiBox<'a, llvm::Builder>,
    values: RefCell<ScopedTable<*const llvm::Value>>,
}

impl<'a> CodeGenerator<'a> {
    fn new(ctxt: &'a Context<'a>) -> CodeGenerator<'a> {
        CodeGenerator {
            ctxt: ctxt,
            types: ctxt.types.borrow(),
            functions: ctxt.functions.borrow(),
            llvm: &ctxt.llvm,
            module: llvm::Module::new(&ctxt.filename, &ctxt.llvm),
            builder: llvm::Builder::new(&ctxt.llvm),
            values: RefCell::new(ScopedTable::new()),
        }
    }

    fn codegen(&self) {
        self.codegen_root(&self.ctxt.ast.borrow());

        println!("{:?}", self.module);
        self.module.verify().unwrap();

        {
            let init = self.module.get_function(GLOBAL_INIT_FN_NAME).unwrap();
            let ee = llvm::JitEngine::new(&self.module, llvm::JitOptions { opt_level: 0 }).unwrap();
            //let ee = llvm::Interpreter::new(&self.module, ()).unwrap();
            ee.with_function(init, |init: extern fn(())| {
                init(());
            });
        }
    }

    fn codegen_root(&self, root: &Root) {
        let unit_ty = llvm::Type::get::<()>(self.llvm);
        let init_fn = self.module.add_function(GLOBAL_INIT_FN_NAME,
                                               llvm::Type::new_function(unit_ty, &[]));
        let mut block = init_fn.append("entry");
        self.builder.position_at_end(block);

        for item in root {
            match *item {
                Item::Assignment(ref x) => {
                    self.builder.position_at_end(block);
                    self.codegen_global_assignment(x, init_fn);
                    block = self.builder.get_position();
                },
                Item::FunctionDef(ref x) => {
                    self.codegen_global_function(x);
                }
            }
        }

        self.builder.build_ret_void();
    }

    fn codegen_global_function(&self, func: &FunctionDef) {
        let ident = func.ident();
        if !self.functions.get(ident).unwrap().has_concrete_type() {
            return; // in other words, the function was never used, so the type of it's signature is unknown
        }
        let name = self.ctxt.lookup_name(ident);
        let ty = self.type_to_llvm(self.types.get_symbol(ident).unwrap().val);
        let num_args = func.args().len();
        println!("TYPE {:?}", ty);
        let llvm_func = self.module.add_function(&name, ty);
        self.values.borrow_mut().set_val(ident, func.ident_pos().index,
                                         llvm_func as *const llvm::Function as *const llvm::Value);
        let entry = llvm_func.append("entry");
        self.builder.position_at_end(entry);
        self.values.borrow_mut().push(func.ident_pos().index);
        for i in 0..num_args {
            let ref arg = func.args()[i];
            &llvm_func[i].set_name(&self.ctxt.lookup_name(arg.ident().unwrap()));
            self.values.borrow_mut().set_val(arg.ident().unwrap(), arg.pos().index,
                                             &llvm_func[i] as *const llvm::Arg as *const llvm::Value);
        }
        let res = self.codegen_block(&func.block, llvm_func);
        self.builder.build_ret(res);
        self.values.borrow_mut().pop();
    }

    fn codegen_global_assignment(&self, assign: &Assignment, func: &llvm::Function) {
        let synt_ty = self.types.get_symbol(assign.ident()).unwrap().val;
        let ty = self.type_to_llvm(synt_ty);
        let name = &self.ctxt.lookup_name(assign.ident());
        let global = self.module.add_global(name, ty);
        global.set_initializer(llvm::Value::new_undef(ty));
        let val = self.codegen_expr(assign.expr(), func);
        self.builder.build_store(val, global);

        // hopefully there's some way to make this not use raw pointers.
        self.values.borrow_mut().set_val(assign.ident(), assign.ident_pos().index,
                                         global as *const llvm::GlobalValue as *const llvm::Value);
    }

    fn codegen_assignment(&self, assign: &Assignment, func: &llvm::Function) {
        let name = &self.ctxt.lookup_name(assign.ident());
        let val = self.codegen_expr(assign.expr(), func);
        val.set_name(name);

        // hopefully there's some way to make this not use raw pointers.
        self.values.borrow_mut().set_val(assign.ident(), assign.ident_pos().index,
                                         val as *const llvm::Value);
    }

    fn codegen_expr(&self, expr: &Expression, func: &llvm::Function) -> &llvm::Value {
        match *expr {
            Expression::Constant(Node(v, _)) => v.compile(self.llvm),
            Expression::Boolean(Node(v, _)) => v.compile(self.llvm),
            Expression::Infix(ref v) => self.codegen_infix(v, func),
            Expression::Prefix(ref v) => self.codegen_prefix(v, func),
            Expression::Variable(ref v) => self.codegen_var(**v, func),
            Expression::Conditional(ref v) => self.codegen_conditional(v, func),
            Expression::Block(ref v) => self.codegen_block(v, func),
            _ => unimplemented!(),
        }
    }

    fn codegen_block(&self, block: &Node<Block>, func: &llvm::Function) -> &llvm::Value {
        self.values.borrow_mut().push(block.pos().index);
        let mut value = None;
        for stmnt in block.item() {
            match *stmnt {
                Statement::Assignment(ref v) => {
                    self.codegen_assignment(v, func);
                },
                Statement::Expression(ref v) => {
                    let expr = self.codegen_expr(v, func);
                    if expr.get_type().is_float() {
                        value = match value {
                            None => Some(expr),
                            Some(v) => Some(self.builder.build_add(v, expr)),
                        };
                    } else {
                        value = Some(expr);
                    }
                },
            }
        }
        self.values.borrow_mut().pop();
        value.unwrap()
    }

    fn codegen_var(&self, ident: Identifier, _: &llvm::Function) -> &llvm::Value {
        let values = self.values.borrow();
        let sym = values.get_symbol(ident).unwrap();
        let value = unsafe { &*sym.val };
        if llvm::GlobalValue::cast(value).is_some() {
            self.builder.build_load(value)
        } else {
            value
        }
    }

    fn codegen_conditional(&self, cond: &Conditional, func: &llvm::Function) -> &llvm::Value {
        let cond_val = self.codegen_expr(cond.cond(), func);
        let then_block = func.append("then");
        let else_block = func.append("else");
        self.builder.build_cond_br(cond_val, then_block, Some(else_block));

        let merge_block = func.append("merge");

        self.builder.position_at_end(then_block);
        let then_val = self.codegen_expr(cond.then(), func);
        self.builder.build_br(merge_block);
        let then_block = self.builder.get_position();

        self.builder.position_at_end(else_block);
        let else_val = self.codegen_expr(cond.els(), func);
        self.builder.build_br(merge_block);
        let else_block = self.builder.get_position();

        self.builder.position_at_end(merge_block);
        assert!(then_val.get_type() == else_val.get_type());
        let phi = self.builder.build_phi(then_val.get_type(), "iftmp");
        phi.add_incoming(then_val, then_block);
        phi.add_incoming(else_val, else_block);
        phi
    }

    fn codegen_infix(&self, infix: &Infix, func: &llvm::Function) -> &llvm::Value {
        let lhs = self.codegen_expr(infix.left(), func);
        let rhs = self.codegen_expr(infix.right(), func);
        match infix.op() {
            Operator::Add => self.builder.build_add(lhs, rhs),
            Operator::Sub => self.builder.build_sub(lhs, rhs),
            Operator::Mul => self.builder.build_mul(lhs, rhs),
            Operator::Div => self.builder.build_div(lhs, rhs),
            Operator::Less => self.builder.build_cmp(lhs, rhs, llvm::Predicate::LessThan),
            Operator::Greater => self.builder.build_cmp(lhs, rhs, llvm::Predicate::GreaterThan),
            Operator::LessEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::LessThanOrEqual),
            Operator::GreaterEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::GreaterThanOrEqual),
            Operator::Equal => self.builder.build_cmp(lhs, rhs, llvm::Predicate::Equal),
            Operator::NotEqual => self.builder.build_cmp(lhs, rhs, llvm::Predicate::NotEqual),
            Operator::Or => self.builder.build_or(lhs, rhs),
            Operator::And => self.builder.build_and(lhs, rhs),
            Operator::Xor => self.builder.build_xor(lhs, rhs),
            _ => unreachable!(),
        }
    }

    fn codegen_prefix(&self, prefix: &Prefix, func: &llvm::Function) -> &llvm::Value {
        let expr = self.codegen_expr(prefix.expr(), func);
        match prefix.op() {
            Operator::Sub => self.builder.build_sub(0f32.compile(self.llvm), expr),
            Operator::Not => self.builder.build_not(expr),
            _ => unreachable!(),
        }
    }

    fn type_to_llvm(&self, ty: Type) -> &llvm::Type {
        match ty {
            Type::Number => llvm::Type::get::<Number>(self.llvm),
            Type::Boolean => llvm::Type::get::<Boolean>(self.llvm),
            Type::Function(id) => {
                let func = self.functions.get(id).unwrap();
                let ty = match *func {
                    functions::Function::User(ref f) => f.ty.as_ref().unwrap(),
                    functions::Function::Builtin(ref f) => &f.ty,
                };
                let args: Vec<&llvm::Type> = ty.args.iter().map(|(_, &ty)| self.type_to_llvm(ty)).collect();
                let ret = self.type_to_llvm(ty.returns);
                llvm::Type::new_function(ret, &args)
            }
            _ => unreachable!(),
        }
    }
}

<|endoftext|>


<commit_before>//! Contains functions for computing SCCs and serializing graphs.
use std::io::{stderr, Read, Write, BufRead, BufReader, BufWriter};
use petgraph::{Graph};
use petgraph::algo::scc;
use petgraph::graph::NodeIndex;
use std::collections::HashMap;

fn load_graph<R>(source: &mut BufReader<R>) -> (Graph<u64, ()>, HashMap<u64, NodeIndex>) where R: Read {
    // read graph size
    let mut size = String::new();
    source.read_line(&mut size).ok().expect("failed to read graph size");

    let sz = size.trim().parse::<i64>().unwrap();
    writeln!(&mut stderr(), "Graph size is {} edges. Loading...", sz).unwrap();

    let mut graph = Graph::<u64, ()>::new();
    let mut nodes = HashMap::new();

    for line in source.lines() {
        let l = line.unwrap();
        let (s, e, o) = scan_fmt!(&l, "{} {} {}", u64, u64, u8);
        let (start, end, oneway) = (s.unwrap(), e.unwrap(), o.unwrap());

        if start == end {
            continue
        }

        // adding a node erases the index, so for each unique index we need to keep
        // a map of the corresponding node <-> internal node id mappings. shitty,
        // but it seems to work.
        if !nodes.contains_key(&start) {
            let sn = graph.add_node(0);
            nodes.insert(start, sn);
        }

        if !nodes.contains_key(&end) {
            let en = graph.add_node(0);
            nodes.insert(end, en);
        }

        let si = nodes.get(&start).unwrap();
        let ei = nodes.get(&end).unwrap();

        graph.update_edge(*si, *ei, ());

        if oneway != 1 {
            graph.update_edge(*ei, *si, ());
        }
    }

    (graph, nodes)
}

/// Computes the strongly connected components. Takes a graph stream as an
/// input where the format is as follows:
///
/// ```
/// num_edges
/// id1 id2 oneway
/// id1 id2 oneway
/// ...
/// id1 id2 oneway
/// ```
///
/// where `id1` is the start of the edge, `id2` is the end of the edge,
/// and `oneway` is **0** if the edge is bidirectional (id2->id1 is permitted)
/// or **1** if `id2` -> `id1` is not allowed. `num_edges` is the number of edges in the
/// file.
pub fn compute<R>(source: &mut BufReader<R>) -> Vec<Vec<u64>> where R: Read {
    let (graph, nodes) = load_graph(source);
    writeln!(&mut stderr(), "Graph loaded. Computing SCCs.").unwrap();
    let mut comps: Vec<Vec<_>> = scc(&graph);
    writeln!(&mut stderr(), "Calculated {} components.", comps.len()).unwrap();

    // sort by size, and reverse
    comps.sort_by(|v, w| v.len().cmp(&w.len()));
    comps.reverse();
    // find out the real nodes
    let inverse_nodes: HashMap<_,_> = nodes.into_iter().map(|(k, v)| (v, k)).collect();
    let mut real_comps = Vec::new();
    for comp in comps {
        let real_nodes = comp.into_iter().map(|n| *inverse_nodes.get(&n).unwrap()).collect();
        real_comps.push(real_nodes);
    }
    real_comps
}

/// Serializes the contents of the components into a file where each node is
/// separated by `delim`. Panics if target cannot be opened.
pub fn serialize<W>(comps: Vec<Vec<u64>>, target: &mut BufWriter<W>, delim: u8) where W: Write {
    for comp in comps[1..].iter() {
        for node in comp {
            target.write(node.to_string().as_bytes()).unwrap();
            target.write(&[delim]).unwrap();
        }
    }
}
<commit_msg>Fix docs.<commit_after>//! Contains functions for computing SCCs and serializing graphs.
use std::io::{stderr, Read, Write, BufRead, BufReader, BufWriter};
use petgraph::{Graph};
use petgraph::algo::scc;
use petgraph::graph::NodeIndex;
use std::collections::HashMap;

fn load_graph<R>(source: &mut BufReader<R>) -> (Graph<u64, ()>, HashMap<u64, NodeIndex>) where R: Read {
    // read graph size
    let mut size = String::new();
    source.read_line(&mut size).ok().expect("failed to read graph size");

    let sz = size.trim().parse::<i64>().unwrap();
    writeln!(&mut stderr(), "Graph size is {} edges. Loading...", sz).unwrap();

    let mut graph = Graph::<u64, ()>::new();
    let mut nodes = HashMap::new();

    for line in source.lines() {
        let l = line.unwrap();
        let (s, e, o) = scan_fmt!(&l, "{} {} {}", u64, u64, u8);
        let (start, end, oneway) = (s.unwrap(), e.unwrap(), o.unwrap());

        if start == end {
            continue
        }

        // adding a node erases the index, so for each unique index we need to keep
        // a map of the corresponding node <-> internal node id mappings. shitty,
        // but it seems to work.
        if !nodes.contains_key(&start) {
            let sn = graph.add_node(0);
            nodes.insert(start, sn);
        }

        if !nodes.contains_key(&end) {
            let en = graph.add_node(0);
            nodes.insert(end, en);
        }

        let si = nodes.get(&start).unwrap();
        let ei = nodes.get(&end).unwrap();

        graph.update_edge(*si, *ei, ());

        if oneway != 1 {
            graph.update_edge(*ei, *si, ());
        }
    }

    (graph, nodes)
}

/// Computes the strongly connected components. Takes a graph stream as an
/// input where the format is as follows:
///
/// ```
/// num_edges
/// id1 id2 oneway
/// id1 id2 oneway
/// ...
/// id1 id2 oneway
/// ```
///
/// where `id1` is the start of the edge, `id2` is the end of the edge,
/// and `oneway` is **0** if the edge is bidirectional (id2->id1 is permitted)
/// or **1** if `id2` -> `id1` is not allowed. `num_edges` is the number of edges in the
/// file.
pub fn compute<R>(source: &mut BufReader<R>) -> Vec<Vec<u64>> where R: Read {
    let (graph, nodes) = load_graph(source);
    writeln!(&mut stderr(), "Graph loaded. Computing SCCs.").unwrap();
    let mut comps: Vec<Vec<_>> = scc(&graph);
    writeln!(&mut stderr(), "Calculated {} components.", comps.len()).unwrap();

    // sort by size, and reverse
    comps.sort_by(|v, w| v.len().cmp(&w.len()));
    comps.reverse();
    // find out the real nodes
    let inverse_nodes: HashMap<_,_> = nodes.into_iter().map(|(k, v)| (v, k)).collect();
    let mut real_comps = Vec::new();
    for comp in comps {
        let real_nodes = comp.into_iter().map(|n| *inverse_nodes.get(&n).unwrap()).collect();
        real_comps.push(real_nodes);
    }
    real_comps
}

/// Serializes the contents of the components into a stream where each node is
/// separated by `delim`. Panics if target cannot be opened.
pub fn serialize<W>(comps: Vec<Vec<u64>>, target: &mut BufWriter<W>, delim: u8) where W: Write {
    for comp in comps[1..].iter() {
        for node in comp {
            target.write(node.to_string().as_bytes()).unwrap();
            target.write(&[delim]).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>// TODO: restructure this file

use rocket;
use modular_flow::graph::{InPortID, NodeID, OutPortID};
use std::sync::Arc;
use rocket_contrib::{Json, Value};
use rocket::{Request, Response, State};
use rocket::http::Status;
use rocket::response::Responder;
use rocket_cors;
use control::*;
use serialize;
use std::thread;
use ws::listen;
use std::time::Duration;

struct WebApi {
    inst: Instance,
}

impl WebApi {
    fn new(inst: Instance) -> WebApi {
        WebApi { inst }
    }

    fn node(&self, id: NodeID) -> Result<Arc<NodeInstance>, JsonErr> {
        self.inst.nodes.node(id).ok_or(JsonErr(Json(json!("invalid node"))))
    }

    fn remove_node(&self, id: NodeID) -> Result<(), JsonErr> {
        // TODO error
        self.inst.nodes.remove(id);
        Ok(())
    }

    fn state_json(&self) -> JsonResult {
        let nodes = self.inst.nodes.nodes();
        let nodes: Vec<_> = nodes
            .iter()
            .map(|node| {
                // TODO better abstraction
                let in_ports: Vec<_> = node.ctl
                    .node()
                    .in_ports()
                    .iter()
                    .enumerate()
                    .map(|(idx, port)| {
                        port.edge()
                            .map(|edge| {
                                json!({
                                    "edge": {
                                        "node": edge.node.0,
                                        "port": edge.port.0,
                                    },
                                    "id": idx,
                                    "name": port.name(),

                                })
                            })
                            .unwrap_or(json!({"id": idx, "name": port.name() }))
                    })
                    .collect();
                let out_ports: Vec<_> = node.ctl
                    .node()
                    .out_ports()
                    .iter()
                    .enumerate()
                    .map(|(idx, port)| {
                        port.edge()
                            .map(|edge| {
                                json!({
                                    "edge": {
                                        "node": edge.node.0,
                                        "port": edge.port.0,
                                    },
                                    "id": idx,
                                    "name": port.name(),

                                })
                            })
                            .unwrap_or(json!({"id": idx, "name": port.name() }))
                    })
                    .collect();
                let message_descriptors: Vec<_> = node.ctl
                    .message_descriptors()
                    .iter()
                    .enumerate()
                    .map(|(idx, msg)| {
                        json!({
                            "id": idx,
                            "name": msg.name,
                            "args": msg.args.iter().map(|arg|
                                                        json!({
                                                            "name": arg.name,
                                                            "type": format!("{:?}", arg.ty),
                                                        })).collect::<Vec<_>>(),
                        })
                    })
                    .collect();
                json!({
                    "id": node.ctl.node().id().0,
                    "type_name": node.type_name,
                    "ports": {
                        "in": in_ports,
                        "out": out_ports,
                    },
                    "status": status_string(node),
                    "message_descriptors": message_descriptors,
                })
            })
            .collect();
        let types: Vec<_> = self.inst.types
            .nodes()
            .iter()
            .map(|node| {
                json!({
                    "name": node.name
                })
            })
            .collect();
        let libs: Vec<_> = self.inst.types.libs().iter().map(|lib| {
            json!({
                "name": lib.name,
                "path": lib.path,
            })
        }).collect();
        resp_ok(json!({
            "nodes": nodes,
            "types": types,
            "libs": libs,
        }))
    }
}

#[get("/state")]
fn state_info(this: State<Arc<WebApi>>) -> JsonResult {
    this.state_json()
}

fn status_string(node: &NodeInstance) -> &'static str {
    if node.ctl.stopped() {
        "stopped"
    } else {
        "running"
    }
}

//TODO make this post so names can contain arbitrary characters
#[get("/type/new/<name>")]
fn node_create(this: State<Arc<WebApi>>, name: String) -> JsonResult {
    let desc = this.inst.types.node(&name).ok_or(JsonErr(Json(json!("id out of bounds"))))?;
    let ctl = (desc.new)(this.inst.ctx.clone(), NewNodeConfig::empty());
    let id = ctl.node().id().0;
    this.inst.nodes.insert(NodeInstance {
        ctl,
        type_name: desc.name,
    });
    resp_ok(json!({
        "id": id,
    }))
}

#[get("/node/connect/<src_node_id>/<src_port_id>/to/<dst_node_id>/<dst_port_id>")]
fn connect_port(
    this: State<Arc<WebApi>>,
    src_node_id: usize,
    src_port_id: usize,
    dst_node_id: usize,
    dst_port_id: usize,
) -> JsonResult {
    match this.inst.ctx.graph().connect(
        NodeID(src_node_id),
        OutPortID(src_port_id),
        NodeID(dst_node_id),
        InPortID(dst_port_id),
    ) {
        Err(_) => resp_err(json!("cannot connect")),
        Ok(_) => resp_ok(json!({})),
    }
}

#[get("/node/disconnect/<node_id>/<port_id>")]
fn disconnect_port(this: State<Arc<WebApi>>, node_id: usize, port_id: usize) -> JsonResult {
    let node = this.inst.ctx.graph().node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("invalid node id"))))?;
    let port = node.in_port(InPortID(port_id)).map_err(|_| JsonErr(Json(json!("invalid port id"))))?;
    match this.inst.ctx.graph().disconnect_in(port) {
        Err(_) => resp_err(json!("cannot disconnect: already connected")),
        Ok(_) => resp_ok(json!({})),
    }
}
#[get("/node/kill/<node_id>")]
fn set_node_status(this: State<Arc<WebApi>>, node_id: usize) -> JsonResult {
    this.inst.kill_node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("couldn't kill node"))))?;
    resp_ok(json!({}))
}
#[get("/node/reload/<node_id>")]
fn reload_node(this: State<Arc<WebApi>>, node_id: usize) -> JsonResult {
    this.inst.reload_node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("couldn't reload node"))))?;
    resp_ok(json!({}))
}

#[post("/node/send_message/<node_id>/<message_id>", format = "application/json", data = "<args>")]
fn send_message(
    this: State<Arc<WebApi>>,
    node_id: usize,
    message_id: usize,
    args: Json<Vec<String>>,
) -> JsonResult {
    use self::message::*;
    let node = this.node(NodeID(node_id))?;
    let message_descriptor = &node.ctl.message_descriptors()[message_id];
    let args = args.0;
    if args.iter().count() != message_descriptor.args.len() {
        return resp_err(json!("wrong arg count"));
    }
    let parsed_args: Result<Vec<_>, _> = args.iter()
        .zip(message_descriptor.args.iter())
        .map(|(arg, desc)| {
            Ok(match desc.ty {
                Type::Bool => Value::Bool(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?),
                Type::Usize => Value::Usize(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?),
                Type::F32 => {
                    Value::F32(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?)
                }
                Type::String => Value::String(arg.clone()),
            })
        })
        .collect();
    let message = Message {
        desc: message_descriptor.clone(),
        args: parsed_args?,
    };
    node.ctl.send_message(message);
    resp_ok(json!({}))
}

#[post("/type/load_library", format = "application/json", data = "<path>")]
fn load_library(this: State<Arc<WebApi>>, path: Json<String>) -> JsonResult {
    this.inst.load_lib(&path);
    resp_ok(json!({}))
}

fn run_notifier(api: Arc<WebApi>) {
    thread::spawn(move || {
        let api = api.clone();
        listen("127.0.0.1:3012", move |out| {
            let api = api.clone();
            thread::spawn(move || {
                let mut prev_nodes_str = "".into();
                loop {
                    thread::sleep(Duration::from_millis(100));
                    let state_str =
                        format!("{}", api.state_json().map(|x| (x.0).0).unwrap_or_else(|x| (x.0).0));
                    if state_str != prev_nodes_str {
                        out.send(state_str.clone()).unwrap();
                        serialize::to_file("dump.json", &api.inst);
                        prev_nodes_str = state_str;
                    }
                }
            });
            |_| Ok(())
        }).unwrap()
    });
}

pub fn run_server(inst: Instance) {
    let api = Arc::new(WebApi::new(inst));
    run_notifier(api.clone());
    let options = rocket_cors::Cors::default();
    rocket::ignite()
        .mount(
            "/",
            routes![
                state_info,
                node_create,
                connect_port,
                disconnect_port,
                set_node_status,
                reload_node,
                send_message,
                load_library,
            ],
        )
        .manage(api)
        .attach(options)
        .launch();
}

#[derive(Debug)]
struct JsonErr(Json<Value>);
struct JsonOk(Json<Value>);

type JsonResult = Result<JsonOk, JsonErr>;

fn resp_err(data: Value) -> JsonResult {
    Err(JsonErr(Json(data)))
}
fn resp_ok(data: Value) -> JsonResult {
    Ok(JsonOk(Json(data)))
}

impl Responder<'static> for JsonOk {
    fn respond_to(self, req: &Request) -> Result<Response<'static>, Status> {
        let JsonOk(json) = self;
        let Json(value) = json;
        let out = Json(json!({
            "status": "ok",
            "data": value,
        }));
        out.respond_to(req)
    }
}

impl Responder<'static> for JsonErr {
    fn respond_to(self, req: &Request) -> Result<Response<'static>, Status> {
        let JsonErr(json) = self;
        let Json(value) = json;
        let out = Json(json!({
            "status": "err",
            "data": value,
        }));
        out.respond_to(req)
    }
}
<commit_msg>include extra node data in json to ensure it gets serialized on change<commit_after>// TODO: restructure this file

use rocket;
use modular_flow::graph::{InPortID, NodeID, OutPortID};
use std::sync::Arc;
use rocket_contrib::{Json, Value};
use rocket::{Request, Response, State};
use rocket::http::Status;
use rocket::response::Responder;
use rocket_cors;
use control::*;
use serialize;
use std::thread;
use ws::listen;
use std::time::Duration;

struct WebApi {
    inst: Instance,
}

impl WebApi {
    fn new(inst: Instance) -> WebApi {
        WebApi { inst }
    }

    fn node(&self, id: NodeID) -> Result<Arc<NodeInstance>, JsonErr> {
        self.inst.nodes.node(id).ok_or(JsonErr(Json(json!("invalid node"))))
    }

    fn remove_node(&self, id: NodeID) -> Result<(), JsonErr> {
        // TODO error
        self.inst.nodes.remove(id);
        Ok(())
    }

    fn state_json(&self) -> JsonResult {
        let nodes = self.inst.nodes.nodes();
        let nodes: Vec<_> = nodes
            .iter()
            .map(|node| {
                // TODO better abstraction
                let in_ports: Vec<_> = node.ctl
                    .node()
                    .in_ports()
                    .iter()
                    .enumerate()
                    .map(|(idx, port)| {
                        port.edge()
                            .map(|edge| {
                                json!({
                                    "edge": {
                                        "node": edge.node.0,
                                        "port": edge.port.0,
                                    },
                                    "id": idx,
                                    "name": port.name(),

                                })
                            })
                            .unwrap_or(json!({"id": idx, "name": port.name() }))
                    })
                    .collect();
                let out_ports: Vec<_> = node.ctl
                    .node()
                    .out_ports()
                    .iter()
                    .enumerate()
                    .map(|(idx, port)| {
                        port.edge()
                            .map(|edge| {
                                json!({
                                    "edge": {
                                        "node": edge.node.0,
                                        "port": edge.port.0,
                                    },
                                    "id": idx,
                                    "name": port.name(),

                                })
                            })
                            .unwrap_or(json!({"id": idx, "name": port.name() }))
                    })
                    .collect();
                let message_descriptors: Vec<_> = node.ctl
                    .message_descriptors()
                    .iter()
                    .enumerate()
                    .map(|(idx, msg)| {
                        json!({
                            "id": idx,
                            "name": msg.name,
                            "args": msg.args.iter().map(|arg|
                                                        json!({
                                                            "name": arg.name,
                                                            "type": format!("{:?}", arg.ty),
                                                        })).collect::<Vec<_>>(),
                        })
                    })
                    .collect();
                json!({
                    "id": node.ctl.node().id().0,
                    "type_name": node.type_name,
                    "ports": {
                        "in": in_ports,
                        "out": out_ports,
                    },
                    "status": status_string(node),
                    "message_descriptors": message_descriptors,
                    "data": node.ctl.saved_data(),
                })
            })
            .collect();
        let types: Vec<_> = self.inst.types
            .nodes()
            .iter()
            .map(|node| {
                json!({
                    "name": node.name
                })
            })
            .collect();
        let libs: Vec<_> = self.inst.types.libs().iter().map(|lib| {
            json!({
                "name": lib.name,
                "path": lib.path,
            })
        }).collect();
        resp_ok(json!({
            "nodes": nodes,
            "types": types,
            "libs": libs,
        }))
    }
}

#[get("/state")]
fn state_info(this: State<Arc<WebApi>>) -> JsonResult {
    this.state_json()
}

fn status_string(node: &NodeInstance) -> &'static str {
    if node.ctl.stopped() {
        "stopped"
    } else {
        "running"
    }
}

//TODO make this post so names can contain arbitrary characters
#[get("/type/new/<name>")]
fn node_create(this: State<Arc<WebApi>>, name: String) -> JsonResult {
    let desc = this.inst.types.node(&name).ok_or(JsonErr(Json(json!("id out of bounds"))))?;
    let ctl = (desc.new)(this.inst.ctx.clone(), NewNodeConfig::empty());
    let id = ctl.node().id().0;
    this.inst.nodes.insert(NodeInstance {
        ctl,
        type_name: desc.name,
    });
    resp_ok(json!({
        "id": id,
    }))
}

#[get("/node/connect/<src_node_id>/<src_port_id>/to/<dst_node_id>/<dst_port_id>")]
fn connect_port(
    this: State<Arc<WebApi>>,
    src_node_id: usize,
    src_port_id: usize,
    dst_node_id: usize,
    dst_port_id: usize,
) -> JsonResult {
    match this.inst.ctx.graph().connect(
        NodeID(src_node_id),
        OutPortID(src_port_id),
        NodeID(dst_node_id),
        InPortID(dst_port_id),
    ) {
        Err(_) => resp_err(json!("cannot connect")),
        Ok(_) => resp_ok(json!({})),
    }
}

#[get("/node/disconnect/<node_id>/<port_id>")]
fn disconnect_port(this: State<Arc<WebApi>>, node_id: usize, port_id: usize) -> JsonResult {
    let node = this.inst.ctx.graph().node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("invalid node id"))))?;
    let port = node.in_port(InPortID(port_id)).map_err(|_| JsonErr(Json(json!("invalid port id"))))?;
    match this.inst.ctx.graph().disconnect_in(port) {
        Err(_) => resp_err(json!("cannot disconnect: already connected")),
        Ok(_) => resp_ok(json!({})),
    }
}
#[get("/node/kill/<node_id>")]
fn set_node_status(this: State<Arc<WebApi>>, node_id: usize) -> JsonResult {
    this.inst.kill_node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("couldn't kill node"))))?;
    resp_ok(json!({}))
}
#[get("/node/reload/<node_id>")]
fn reload_node(this: State<Arc<WebApi>>, node_id: usize) -> JsonResult {
    this.inst.reload_node(NodeID(node_id)).map_err(|_| JsonErr(Json(json!("couldn't reload node"))))?;
    resp_ok(json!({}))
}

#[post("/node/send_message/<node_id>/<message_id>", format = "application/json", data = "<args>")]
fn send_message(
    this: State<Arc<WebApi>>,
    node_id: usize,
    message_id: usize,
    args: Json<Vec<String>>,
) -> JsonResult {
    use self::message::*;
    let node = this.node(NodeID(node_id))?;
    let message_descriptor = &node.ctl.message_descriptors()[message_id];
    let args = args.0;
    if args.iter().count() != message_descriptor.args.len() {
        return resp_err(json!("wrong arg count"));
    }
    let parsed_args: Result<Vec<_>, _> = args.iter()
        .zip(message_descriptor.args.iter())
        .map(|(arg, desc)| {
            Ok(match desc.ty {
                Type::Bool => Value::Bool(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?),
                Type::Usize => Value::Usize(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?),
                Type::F32 => {
                    Value::F32(arg.parse().map_err(|e| JsonErr(Json(json!(format!("{:?}", e)))))?)
                }
                Type::String => Value::String(arg.clone()),
            })
        })
        .collect();
    let message = Message {
        desc: message_descriptor.clone(),
        args: parsed_args?,
    };
    node.ctl.send_message(message);
    resp_ok(json!({}))
}

#[post("/type/load_library", format = "application/json", data = "<path>")]
fn load_library(this: State<Arc<WebApi>>, path: Json<String>) -> JsonResult {
    this.inst.load_lib(&path);
    resp_ok(json!({}))
}

fn run_notifier(api: Arc<WebApi>) {
    thread::spawn(move || {
        let api = api.clone();
        listen("127.0.0.1:3012", move |out| {
            let api = api.clone();
            thread::spawn(move || {
                let mut prev_nodes_str = "".into();
                loop {
                    thread::sleep(Duration::from_millis(100));
                    let state_str =
                        format!("{}", api.state_json().map(|x| (x.0).0).unwrap_or_else(|x| (x.0).0));
                    if state_str != prev_nodes_str {
                        out.send(state_str.clone()).unwrap();
                        serialize::to_file("dump.json", &api.inst);
                        prev_nodes_str = state_str;
                    }
                }
            });
            |_| Ok(())
        }).unwrap()
    });
}

pub fn run_server(inst: Instance) {
    let api = Arc::new(WebApi::new(inst));
    run_notifier(api.clone());
    let options = rocket_cors::Cors::default();
    rocket::ignite()
        .mount(
            "/",
            routes![
                state_info,
                node_create,
                connect_port,
                disconnect_port,
                set_node_status,
                reload_node,
                send_message,
                load_library,
            ],
        )
        .manage(api)
        .attach(options)
        .launch();
}

#[derive(Debug)]
struct JsonErr(Json<Value>);
struct JsonOk(Json<Value>);

type JsonResult = Result<JsonOk, JsonErr>;

fn resp_err(data: Value) -> JsonResult {
    Err(JsonErr(Json(data)))
}
fn resp_ok(data: Value) -> JsonResult {
    Ok(JsonOk(Json(data)))
}

impl Responder<'static> for JsonOk {
    fn respond_to(self, req: &Request) -> Result<Response<'static>, Status> {
        let JsonOk(json) = self;
        let Json(value) = json;
        let out = Json(json!({
            "status": "ok",
            "data": value,
        }));
        out.respond_to(req)
    }
}

impl Responder<'static> for JsonErr {
    fn respond_to(self, req: &Request) -> Result<Response<'static>, Status> {
        let JsonErr(json) = self;
        let Json(value) = json;
        let out = Json(json!({
            "status": "err",
            "data": value,
        }));
        out.respond_to(req)
    }
}
<|endoftext|>


<commit_before><commit_msg>explain let_base_ptr<commit_after><|endoftext|>