<commit_before>
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum ListingOrderBy {
    #[serde(rename = "id")]
    Id,
    #[serde(rename = "name")]
    Name,
    #[serde(rename = "path")]
    Path,
    #[serde(rename = "created_at")]
    CreatedAt,
    #[serde(rename = "updated_at")]
    UpdatedAt,
    #[serde(rename = "last_activity_at")]
    LastActivityAt,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ProjectListerInternal {
    /// Limit by archived status
    archived: Option<bool>,
    /// Limit by visibility.
    visibility: Option<::ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by: Option<ListingOrderBy>,
    /// Return requests sorted. Default is `::ListingSort::Desc`.
    sort: Option<::ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search: Option<String>,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct OwnedProjectListerInternal {

}
<commit_msg>Add members to `OwnedProjectListerInternal`<commit_after>
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum ListingOrderBy {
    #[serde(rename = "id")]
    Id,
    #[serde(rename = "name")]
    Name,
    #[serde(rename = "path")]
    Path,
    #[serde(rename = "created_at")]
    CreatedAt,
    #[serde(rename = "updated_at")]
    UpdatedAt,
    #[serde(rename = "last_activity_at")]
    LastActivityAt,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ProjectListerInternal {
    /// Limit by archived status
    archived: Option<bool>,
    /// Limit by visibility.
    visibility: Option<::ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by: Option<ListingOrderBy>,
    /// Return requests sorted. Default is `::ListingSort::Desc`.
    sort: Option<::ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search: Option<String>,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct OwnedProjectListerInternal {
    /// Limit by archived status
    archived: Option<bool>,
    /// Limit by visibility.
    visibility: Option<::ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by: Option<ListingOrderBy>,
    /// Return requests sorted. Default is `::ListingSort::Desc`.
    sort: Option<::ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search: Option<String>,
}
<|endoftext|>


<commit_before>use rocket::{self, Rocket, State };
use rocket::logger::LoggingLevel;
use rocket_contrib::JSON;
use rocket::response::{Response, Responder};
use rocket::request::{self, FromRequest, Request};
use rocket::Outcome;
use rocket::http::{Status, Cookie, Cookies};
use rocket::config::{Environment, Config};
use adapters::json;
use entities::*;
use business::db::Db;
use business::error::{Error, RepoError, ParameterError};
use infrastructure::error::AppError;
use serde_json::ser::to_string;
use business::sort::SortByAverageRating;
use business::{usecase, filter, geo};
use business::filter::InBBox;
use business::duplicates::{self, DuplicateType};
use std::{result,thread,env};
use r2d2::{self, Pool};
use regex::Regex;
use super::mail;
use super::cfg;

static MAX_INVISIBLE_RESULTS : usize = 5;
static COOKIE_USER_KEY       : &str  = "user_id";

lazy_static! {
    static ref CONFIG: cfg::Config = {
        match env::current_dir() {
            Ok(cwd) => {
                let path = cwd.as_path().join("config.toml");
                match cfg::Config::load(path) {
                    Ok(cfg) => cfg,
                    Err(e) => {
                        warn!("could not read configuration file 'config.toml': {}", e);
                        cfg::Config::default()
                    }
                }
            }
            Err(e) => {
                warn!("could not determine current working directory: {}", e);
                cfg::Config::default()
            }
        }
    };
}

mod neo4j;
#[cfg(test)]
mod mockdb;
#[cfg(test)]
mod tests;

#[cfg(not(test))]
type DbPool = neo4j::ConnectionPool;
#[cfg(test)]
type DbPool = mockdb::ConnectionPool;

type Result<T> = result::Result<JSON<T>, AppError>;

fn extract_ids(s: &str) -> Vec<String> {
    s.split(',')
        .map(|x| x.to_owned())
        .filter(|id| id != "")
        .collect::<Vec<String>>()
}

#[derive(Debug)]
struct User(String);

impl<'a, 'r> FromRequest<'a, 'r> for User {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<User, ()> {
        let user = request.cookies()
            .get_private(COOKIE_USER_KEY)
            .and_then(|cookie| cookie.value().parse().ok())
            .map(|id| User(id));
        match user {
            Some(user) => Outcome::Success(user),
            None => Outcome::Failure((Status::Unauthorized, ()))
        }
    }
}

fn notify(subject: &str, body: &str) {
    match mail::create(&CONFIG.notification.send_to, subject, body) {
        Ok(mail) => {
            thread::spawn(move ||{
                if let Err(err) = mail::send(&mail) {
                    warn!("Could not send mail: {}", err);
                }
            });
        }
        Err(e) => {
            warn!("could not create notifiction mail: {}", e);
        }
    }
}

#[get("/entries/<ids>")]
fn get_entry(db: State<DbPool>, ids: String) -> Result<Vec<json::Entry>> {
    let ids = extract_ids(&ids);
    let entries = usecase::get_entries(&*db.get()?, &ids)?;
    let tags = usecase::get_tags_by_entry_ids(&*db.get()?, &ids)?;
    let ratings = usecase::get_ratings_by_entry_ids(&*db.get()?, &ids)?;
    Ok(JSON(entries
        .into_iter()
        .map(|e|{
            let t = tags.get(&e.id).cloned().unwrap_or_else(|| vec![]);
            let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
            json::Entry::from_entry_with_tags_and_ratings(e,t,r)
        })
        .collect::<Vec<json::Entry>>()))
}

#[get("/duplicates")]
fn get_duplicates(db: State<DbPool>) -> Result<Vec<(String, String, DuplicateType)>> {
    let entries = db.get()?.all_entries()?;
    let ids = duplicates::find_duplicates(&entries);
    Ok(JSON(ids))
}

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(db: State<DbPool>, e: JSON<usecase::NewEntry>) -> result::Result<String, AppError> {
    let e = e.into_inner();
    let id = usecase::create_new_entry(&mut *db.get()?, e.clone())?;
    notify(&format!("Neuer Eintrag: {}", e.title),&format!("{:?}",e));
    Ok(id)
}

#[put("/entries/<id>", format = "application/json", data = "<e>")]
fn put_entry(db: State<DbPool>, id: String, e: JSON<usecase::UpdateEntry>) -> Result<String> {
    let e = e.into_inner();
    usecase::update_entry(&mut *db.get()?, e.clone())?;
    notify(&format!("Veränderter Eintrag: {}", e.title),&format!("{:?}",e));
    Ok(JSON(id))
}

#[get("/tags")]
fn get_tags(db: State<DbPool>) -> Result<Vec<String>> {
    let tags = usecase::get_tag_ids(&*db.get()?)?;
    Ok(JSON(tags))
}

#[get("/categories")]
fn get_categories(db: State<DbPool>) -> Result<Vec<Category>> {
    let categories = db.get()?.all_categories()?;
    Ok(JSON(categories))
}

#[get("/categories/<id>")]
fn get_category(db: State<DbPool>, id: String) -> Result<String> {
    let ids = extract_ids(&id);
    let categories = db.get()?.all_categories()?;
    let res = match ids.len() {
        0 => to_string(&categories),

        1 => {
            let id = ids[0].clone();
            let e = categories
                .into_iter()
                .find(|x| x.id == id)
                .ok_or(RepoError::NotFound)?;
            to_string(&e)
        }
        _ => {
            to_string(&categories.into_iter()
                .filter(|e| ids.iter().any(|id| e.id == id.clone()))
                .collect::<Vec<Category>>())
        }
    }?;
    Ok(JSON(res))
}

#[derive(FromForm)]
struct SearchQuery {
    bbox: String,
    categories: Option<String>,
    text: Option<String>,
    tags: Option<String>,
}

lazy_static! {
    static ref HASH_TAG_REGEX: Regex = Regex::new(r"#(?P<tag>\w+((-\w+)*)?)").unwrap();
}

fn extract_hash_tags(text: &str) -> Vec<String> {
    let mut res: Vec<String> = vec![];
    for cap in HASH_TAG_REGEX.captures_iter(text) {
        res.push(cap["tag"].into());
    }
    res
}

fn remove_hash_tags(text: &str) -> String {
    HASH_TAG_REGEX
        .replace_all(text, "")
        .into_owned()
        .replace("  ", " ")
        .trim()
        .into()
}

#[get("/search?<search>")]
fn get_search(db: State<DbPool>, search: SearchQuery) -> Result<json::SearchResult> {

    let entries = db.get()?.all_entries()?;

    let bbox = geo::extract_bbox(&search.bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;
    let bbox_center = geo::center(&bbox[0], &bbox[1]);

    let mut entries: Vec<&Entry> = entries.iter().collect();

    if let Some(cat_str) = search.categories {
        let cat_ids = extract_ids(&cat_str);
        entries = entries
            .into_iter()
            .filter(&*filter::entries_by_category_ids(&cat_ids))
            .collect();
    }

    let mut tags = vec![];

    if let Some(ref txt) = search.text {
        tags = extract_hash_tags(txt);
    }

    if let Some(tags_str) = search.tags {
        for t in extract_ids(&tags_str) {
            tags.push(t);
        }
    }

    // search tags even without preceding #:
    if let Some(ref txt) = search.text {
        for t in to_words(txt){
            tags.push(t);
        }
    }

    let triples = db.get()?.all_triples()?;

    let text = match search.text {
        Some(txt) => remove_hash_tags(&txt),
        None => "".into()
    };

    let entries : Vec<&Entry> = entries
        .into_iter()
        .filter(&*filter::entries_by_tags_or_search_text(&text, &tags, &triples))
        .collect();

    let mut entries : Vec<Entry> = entries.into_iter().cloned().collect();

    let all_ratings = db.get()?.all_ratings()?;

    entries.sort_by_avg_rating(&all_ratings, &triples);

    let visible_results: Vec<_> = entries
        .iter()
        .filter(|x| x.in_bbox(&bbox))
        .map(|x| &x.id)
        .cloned()
        .collect();

    let invisible_results = entries
        .iter()
        .filter(|e| !visible_results.iter().any(|v| *v == e.id))
        .take(MAX_INVISIBLE_RESULTS)
        .map(|x| &x.id)
        .cloned()
        .collect::<Vec<_>>();

    Ok(JSON(json::SearchResult {
        visible: visible_results,
        invisible: invisible_results,
    }))
}

fn to_words(txt: &str) -> Vec<String> {
    txt.to_lowercase().split(' ').map(|x| x.to_string()).collect()
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(db: State<DbPool>, mut cookies: Cookies, login: JSON<usecase::Login>) -> Result<()> {
    let id = usecase::login(&mut*db.get()?, login.into_inner())?;
    cookies.add_private(Cookie::new(COOKIE_USER_KEY, id));
    Ok(JSON(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(JSON(()))
}

#[get("/users/<id>", format = "application/json")]
fn get_user(db: State<DbPool>, user: User, id: String) -> result::Result<JSON<json::User>,AppError> {
    let (username, email) = usecase::get_user(&mut*db.get()?, &user.0, &id)?;
    Ok(JSON(json::User{ username, email }))
}

#[post("/users", format = "application/json", data = "<u>")]
fn post_user(db: State<DbPool>, u: JSON<usecase::NewUser>) -> result::Result<(),AppError> {
    usecase::create_new_user(&mut*db.get()?, u.into_inner())?;
    Ok(())
}

#[post("/ratings", format = "application/json", data = "<u>")]
fn post_rating(db: State<DbPool>, u: JSON<usecase::RateEntry>) -> result::Result<(),AppError> {
    usecase::rate_entry(&mut*db.get()?, u.into_inner())?;
    Ok(())
}

#[get("/ratings/<id>")]
fn get_ratings(db: State<DbPool>, id: String)-> Result<Vec<json::Rating>>{
    let ratings = usecase::get_ratings(&*db.get()?,&extract_ids(&id))?;
    let r_ids : Vec<String> = ratings
        .iter()
        .map(|r|r.id.clone())
        .collect();
    let comments = usecase::get_comments_by_rating_ids(&*db.get()?,&r_ids)?;
    let triples = db.get()?.all_triples()?;
    let result = ratings
        .into_iter()
        .map(|x|json::Rating{
            id       : x.id.clone(),
            created  : x.created,
            title    : x.title,
            user     : usecase::get_user_id_for_rating_id(&triples,&x.id),
            value    : x.value,
            context  : x.context,
            source   : x.source.unwrap_or("".into()),
            comments : comments.get(&x.id).cloned().unwrap_or_else(|| vec![])
                .into_iter()
                .map(|c|json::Comment{
                    id: c.id.clone(),
                    created: c.created,
                    text: c.text,
                    user: usecase::get_user_id_for_comment_id(&triples,&c.id)
                 })
                .collect()
        })
        .collect();
    Ok(JSON(result))
}

#[get("/count/entries")]
fn get_count_entries(db: State<DbPool>) -> Result<usize> {
    let entries = db.get()?.all_entries()?;
    Ok(JSON(entries.len()))
}

#[get("/count/tags")]
fn get_count_tags(db: State<DbPool>) -> Result<usize> {
    let tags = usecase::get_tag_ids(&*db.get()?)?;
    Ok(JSON(tags.len()))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

fn rocket_instance<T: r2d2::ManageConnection>(cfg: Config, pool: Pool<T>) -> Rocket {

    rocket::custom(cfg, true)
        .manage(pool)
        .mount("/",
               routes![login,
                       logout,
                       get_entry,
                       post_entry,
                       post_user,
                       post_rating,
                       put_entry,
                       get_user,
                       get_categories,
                       get_tags,
                       get_ratings,
                       get_category,
                       get_search,
                       get_duplicates,
                       get_count_entries,
                       get_count_tags,
                       get_version])

}

pub fn run(db_url: &str, port: u16, enable_cors: bool) {

    if enable_cors {
        panic!("enable-cors is currently not available until\
        \nhttps://github.com/SergioBenitez/Rocket/pull/141\nis merged :(");
    }

    let cfg = Config::build(Environment::Production)
        .log_level(LoggingLevel::Normal)
        .address("127.0.0.1")
        .port(port)
        .finalize()
        .unwrap();

    let pool = neo4j::create_connection_pool(db_url).unwrap();

    rocket_instance(cfg, pool).launch();
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        Err(match self {
            AppError::Business(ref err) => {
                match *err {
                    Error::Parameter(ref err) => {
                         match *err {
                            ParameterError::Credentials => Status::Unauthorized,
                            _ => Status::BadRequest,
                         }
                    }
                    Error::Repo(ref err) => {
                        match *err {
                            RepoError::NotFound => Status::NotFound,
                            _ => Status::InternalServerError,
                        }
                    }
                    Error::Pwhash(_) => Status::InternalServerError
                }
            }

            _ => Status::InternalServerError,
        })
    }
}
<commit_msg>chore(*): removed unused variable bbox<commit_after>use rocket::{self, Rocket, State };
use rocket::logger::LoggingLevel;
use rocket_contrib::JSON;
use rocket::response::{Response, Responder};
use rocket::request::{self, FromRequest, Request};
use rocket::Outcome;
use rocket::http::{Status, Cookie, Cookies};
use rocket::config::{Environment, Config};
use adapters::json;
use entities::*;
use business::db::Db;
use business::error::{Error, RepoError, ParameterError};
use infrastructure::error::AppError;
use serde_json::ser::to_string;
use business::sort::SortByAverageRating;
use business::{usecase, filter, geo};
use business::filter::InBBox;
use business::duplicates::{self, DuplicateType};
use std::{result,thread,env};
use r2d2::{self, Pool};
use regex::Regex;
use super::mail;
use super::cfg;

static MAX_INVISIBLE_RESULTS : usize = 5;
static COOKIE_USER_KEY       : &str  = "user_id";

lazy_static! {
    static ref CONFIG: cfg::Config = {
        match env::current_dir() {
            Ok(cwd) => {
                let path = cwd.as_path().join("config.toml");
                match cfg::Config::load(path) {
                    Ok(cfg) => cfg,
                    Err(e) => {
                        warn!("could not read configuration file 'config.toml': {}", e);
                        cfg::Config::default()
                    }
                }
            }
            Err(e) => {
                warn!("could not determine current working directory: {}", e);
                cfg::Config::default()
            }
        }
    };
}

mod neo4j;
#[cfg(test)]
mod mockdb;
#[cfg(test)]
mod tests;

#[cfg(not(test))]
type DbPool = neo4j::ConnectionPool;
#[cfg(test)]
type DbPool = mockdb::ConnectionPool;

type Result<T> = result::Result<JSON<T>, AppError>;

fn extract_ids(s: &str) -> Vec<String> {
    s.split(',')
        .map(|x| x.to_owned())
        .filter(|id| id != "")
        .collect::<Vec<String>>()
}

#[derive(Debug)]
struct User(String);

impl<'a, 'r> FromRequest<'a, 'r> for User {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<User, ()> {
        let user = request.cookies()
            .get_private(COOKIE_USER_KEY)
            .and_then(|cookie| cookie.value().parse().ok())
            .map(|id| User(id));
        match user {
            Some(user) => Outcome::Success(user),
            None => Outcome::Failure((Status::Unauthorized, ()))
        }
    }
}

fn notify(subject: &str, body: &str) {
    match mail::create(&CONFIG.notification.send_to, subject, body) {
        Ok(mail) => {
            thread::spawn(move ||{
                if let Err(err) = mail::send(&mail) {
                    warn!("Could not send mail: {}", err);
                }
            });
        }
        Err(e) => {
            warn!("could not create notifiction mail: {}", e);
        }
    }
}

#[get("/entries/<ids>")]
fn get_entry(db: State<DbPool>, ids: String) -> Result<Vec<json::Entry>> {
    let ids = extract_ids(&ids);
    let entries = usecase::get_entries(&*db.get()?, &ids)?;
    let tags = usecase::get_tags_by_entry_ids(&*db.get()?, &ids)?;
    let ratings = usecase::get_ratings_by_entry_ids(&*db.get()?, &ids)?;
    Ok(JSON(entries
        .into_iter()
        .map(|e|{
            let t = tags.get(&e.id).cloned().unwrap_or_else(|| vec![]);
            let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
            json::Entry::from_entry_with_tags_and_ratings(e,t,r)
        })
        .collect::<Vec<json::Entry>>()))
}

#[get("/duplicates")]
fn get_duplicates(db: State<DbPool>) -> Result<Vec<(String, String, DuplicateType)>> {
    let entries = db.get()?.all_entries()?;
    let ids = duplicates::find_duplicates(&entries);
    Ok(JSON(ids))
}

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(db: State<DbPool>, e: JSON<usecase::NewEntry>) -> result::Result<String, AppError> {
    let e = e.into_inner();
    let id = usecase::create_new_entry(&mut *db.get()?, e.clone())?;
    notify(&format!("Neuer Eintrag: {}", e.title),&format!("{:?}",e));
    Ok(id)
}

#[put("/entries/<id>", format = "application/json", data = "<e>")]
fn put_entry(db: State<DbPool>, id: String, e: JSON<usecase::UpdateEntry>) -> Result<String> {
    let e = e.into_inner();
    usecase::update_entry(&mut *db.get()?, e.clone())?;
    notify(&format!("Veränderter Eintrag: {}", e.title),&format!("{:?}",e));
    Ok(JSON(id))
}

#[get("/tags")]
fn get_tags(db: State<DbPool>) -> Result<Vec<String>> {
    let tags = usecase::get_tag_ids(&*db.get()?)?;
    Ok(JSON(tags))
}

#[get("/categories")]
fn get_categories(db: State<DbPool>) -> Result<Vec<Category>> {
    let categories = db.get()?.all_categories()?;
    Ok(JSON(categories))
}

#[get("/categories/<id>")]
fn get_category(db: State<DbPool>, id: String) -> Result<String> {
    let ids = extract_ids(&id);
    let categories = db.get()?.all_categories()?;
    let res = match ids.len() {
        0 => to_string(&categories),

        1 => {
            let id = ids[0].clone();
            let e = categories
                .into_iter()
                .find(|x| x.id == id)
                .ok_or(RepoError::NotFound)?;
            to_string(&e)
        }
        _ => {
            to_string(&categories.into_iter()
                .filter(|e| ids.iter().any(|id| e.id == id.clone()))
                .collect::<Vec<Category>>())
        }
    }?;
    Ok(JSON(res))
}

#[derive(FromForm)]
struct SearchQuery {
    bbox: String,
    categories: Option<String>,
    text: Option<String>,
    tags: Option<String>,
}

lazy_static! {
    static ref HASH_TAG_REGEX: Regex = Regex::new(r"#(?P<tag>\w+((-\w+)*)?)").unwrap();
}

fn extract_hash_tags(text: &str) -> Vec<String> {
    let mut res: Vec<String> = vec![];
    for cap in HASH_TAG_REGEX.captures_iter(text) {
        res.push(cap["tag"].into());
    }
    res
}

fn remove_hash_tags(text: &str) -> String {
    HASH_TAG_REGEX
        .replace_all(text, "")
        .into_owned()
        .replace("  ", " ")
        .trim()
        .into()
}

#[get("/search?<search>")]
fn get_search(db: State<DbPool>, search: SearchQuery) -> Result<json::SearchResult> {

    let entries = db.get()?.all_entries()?;

    let bbox = geo::extract_bbox(&search.bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;

    let mut entries: Vec<&Entry> = entries.iter().collect();

    if let Some(cat_str) = search.categories {
        let cat_ids = extract_ids(&cat_str);
        entries = entries
            .into_iter()
            .filter(&*filter::entries_by_category_ids(&cat_ids))
            .collect();
    }

    let mut tags = vec![];

    if let Some(ref txt) = search.text {
        tags = extract_hash_tags(txt);
    }

    if let Some(tags_str) = search.tags {
        for t in extract_ids(&tags_str) {
            tags.push(t);
        }
    }

    // search tags even without preceding #:
    if let Some(ref txt) = search.text {
        for t in to_words(txt){
            tags.push(t);
        }
    }

    let triples = db.get()?.all_triples()?;

    let text = match search.text {
        Some(txt) => remove_hash_tags(&txt),
        None => "".into()
    };

    let entries : Vec<&Entry> = entries
        .into_iter()
        .filter(&*filter::entries_by_tags_or_search_text(&text, &tags, &triples))
        .collect();

    let mut entries : Vec<Entry> = entries.into_iter().cloned().collect();

    let all_ratings = db.get()?.all_ratings()?;

    entries.sort_by_avg_rating(&all_ratings, &triples);

    let visible_results: Vec<_> = entries
        .iter()
        .filter(|x| x.in_bbox(&bbox))
        .map(|x| &x.id)
        .cloned()
        .collect();

    let invisible_results = entries
        .iter()
        .filter(|e| !visible_results.iter().any(|v| *v == e.id))
        .take(MAX_INVISIBLE_RESULTS)
        .map(|x| &x.id)
        .cloned()
        .collect::<Vec<_>>();

    Ok(JSON(json::SearchResult {
        visible: visible_results,
        invisible: invisible_results,
    }))
}

fn to_words(txt: &str) -> Vec<String> {
    txt.to_lowercase().split(' ').map(|x| x.to_string()).collect()
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(db: State<DbPool>, mut cookies: Cookies, login: JSON<usecase::Login>) -> Result<()> {
    let id = usecase::login(&mut*db.get()?, login.into_inner())?;
    cookies.add_private(Cookie::new(COOKIE_USER_KEY, id));
    Ok(JSON(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(JSON(()))
}

#[get("/users/<id>", format = "application/json")]
fn get_user(db: State<DbPool>, user: User, id: String) -> result::Result<JSON<json::User>,AppError> {
    let (username, email) = usecase::get_user(&mut*db.get()?, &user.0, &id)?;
    Ok(JSON(json::User{ username, email }))
}

#[post("/users", format = "application/json", data = "<u>")]
fn post_user(db: State<DbPool>, u: JSON<usecase::NewUser>) -> result::Result<(),AppError> {
    usecase::create_new_user(&mut*db.get()?, u.into_inner())?;
    Ok(())
}

#[post("/ratings", format = "application/json", data = "<u>")]
fn post_rating(db: State<DbPool>, u: JSON<usecase::RateEntry>) -> result::Result<(),AppError> {
    usecase::rate_entry(&mut*db.get()?, u.into_inner())?;
    Ok(())
}

#[get("/ratings/<id>")]
fn get_ratings(db: State<DbPool>, id: String)-> Result<Vec<json::Rating>>{
    let ratings = usecase::get_ratings(&*db.get()?,&extract_ids(&id))?;
    let r_ids : Vec<String> = ratings
        .iter()
        .map(|r|r.id.clone())
        .collect();
    let comments = usecase::get_comments_by_rating_ids(&*db.get()?,&r_ids)?;
    let triples = db.get()?.all_triples()?;
    let result = ratings
        .into_iter()
        .map(|x|json::Rating{
            id       : x.id.clone(),
            created  : x.created,
            title    : x.title,
            user     : usecase::get_user_id_for_rating_id(&triples,&x.id),
            value    : x.value,
            context  : x.context,
            source   : x.source.unwrap_or("".into()),
            comments : comments.get(&x.id).cloned().unwrap_or_else(|| vec![])
                .into_iter()
                .map(|c|json::Comment{
                    id: c.id.clone(),
                    created: c.created,
                    text: c.text,
                    user: usecase::get_user_id_for_comment_id(&triples,&c.id)
                 })
                .collect()
        })
        .collect();
    Ok(JSON(result))
}

#[get("/count/entries")]
fn get_count_entries(db: State<DbPool>) -> Result<usize> {
    let entries = db.get()?.all_entries()?;
    Ok(JSON(entries.len()))
}

#[get("/count/tags")]
fn get_count_tags(db: State<DbPool>) -> Result<usize> {
    let tags = usecase::get_tag_ids(&*db.get()?)?;
    Ok(JSON(tags.len()))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

fn rocket_instance<T: r2d2::ManageConnection>(cfg: Config, pool: Pool<T>) -> Rocket {

    rocket::custom(cfg, true)
        .manage(pool)
        .mount("/",
               routes![login,
                       logout,
                       get_entry,
                       post_entry,
                       post_user,
                       post_rating,
                       put_entry,
                       get_user,
                       get_categories,
                       get_tags,
                       get_ratings,
                       get_category,
                       get_search,
                       get_duplicates,
                       get_count_entries,
                       get_count_tags,
                       get_version])

}

pub fn run(db_url: &str, port: u16, enable_cors: bool) {

    if enable_cors {
        panic!("enable-cors is currently not available until\
        \nhttps://github.com/SergioBenitez/Rocket/pull/141\nis merged :(");
    }

    let cfg = Config::build(Environment::Production)
        .log_level(LoggingLevel::Normal)
        .address("127.0.0.1")
        .port(port)
        .finalize()
        .unwrap();

    let pool = neo4j::create_connection_pool(db_url).unwrap();

    rocket_instance(cfg, pool).launch();
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        Err(match self {
            AppError::Business(ref err) => {
                match *err {
                    Error::Parameter(ref err) => {
                         match *err {
                            ParameterError::Credentials => Status::Unauthorized,
                            _ => Status::BadRequest,
                         }
                    }
                    Error::Repo(ref err) => {
                        match *err {
                            RepoError::NotFound => Status::NotFound,
                            _ => Status::InternalServerError,
                        }
                    }
                    Error::Pwhash(_) => Status::InternalServerError
                }
            }

            _ => Status::InternalServerError,
        })
    }
}
<|endoftext|>


<commit_before>use super::start_server;
use graph;
use graph::*;
use graph::edge::*;
use graph::vertex::*;
use server::schema::{MorpheusSchema, SchemaError, EMPTY_FIELDS};
use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Value, Map};
use neb::ram::cell::Cell;

#[test]
pub fn schemas() {
    let server = start_server(4001, "schemas");
    let graph = &server.graph;
    let mut edge_schema = MorpheusSchema::new(
        "test_edge_schema",
        None,
        &vec![Field::new(&"test_field", TypeId::U32 as u32, false, false, None)], false
    );
    assert_eq!(edge_schema.id, 0);
    assert!(
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new
            (
                graph::edge::EdgeType::Directed,
                false
            )).is_err());
    assert_eq!(edge_schema.id, 0);
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new(graph::edge::EdgeType::Directed, true)).unwrap();
    let mut vertex_schema = edge_schema.clone();
    vertex_schema.name = "test_vertex_schema".to_string();
    graph.new_vertex_group(&mut vertex_schema).unwrap();
    assert_eq!(edge_schema.id, 1);
    assert_eq!(vertex_schema.id, 2);
    let mut test_data = Map::new();
    test_data.insert("test_field", Value::U32(1));
    graph.new_vertex(&vertex_schema, test_data.clone()).unwrap();
    graph.new_vertex("test_edge_schema", test_data.clone()).is_err();
}

#[test]
pub fn relationship() {
    let server = start_server(4002, "relationship");
    let graph = &server.graph;
    let mut people_schema = MorpheusSchema::new("people", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None)
    ], true);
    let mut movie_schema = MorpheusSchema::new("movie", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None),
        Field::new("year", TypeId::U32 as u32, false, false, None)
    ], true);
    let mut acted_in_schema = MorpheusSchema::new("acted-in", None, &vec! [
        Field::new("role", TypeId::String as u32, false, false, None)
    ], true);
    let mut spouse_schema = MorpheusSchema::new("spouse", None, &EMPTY_FIELDS, false);
    graph.new_vertex_group(&mut people_schema).unwrap();
    graph.new_vertex_group(&mut movie_schema).unwrap();
    graph.new_edge_group(
        &mut acted_in_schema,
        EdgeAttributes::new(
            EdgeType::Directed,
            true
        )
    ).unwrap();
    graph.new_edge_group(
        &mut spouse_schema,
        EdgeAttributes::new(
            EdgeType::Undirected,
            false
        )
    ).unwrap();
    assert_eq!(people_schema.id, 1);
    assert_eq!(movie_schema.id, 2);
    assert_eq!(acted_in_schema.id, 3);
    assert_eq!(spouse_schema.id, 4);
    let morgan_freeman_name = "Morgan Freeman";
    let batman_begins_name = "Batman Begins";
    let the_dark_knight_name = "The Dark Knight";
    let the_dark_knight_rises_name = "The Dark Knight Rises";
    let oblivion_name = "Oblivion";
    let jeanette_name = "Jeanette Adair Bradshaw";
    graph.new_vertex("people", data_map!{
        name: morgan_freeman_name, age: 80 as u8
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: batman_begins_name, year: 2005 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: the_dark_knight_name, year: 2008 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: the_dark_knight_rises_name, year: 2012 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: oblivion_name, year: 2010 as u32
    }).unwrap();
    graph.new_vertex("people", data_map!{
        name: jeanette_name
    }).unwrap();

    assert_eq!(
        graph.vertex_by_key("people", morgan_freeman_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        morgan_freeman_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", batman_begins_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        batman_begins_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", the_dark_knight_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        the_dark_knight_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", the_dark_knight_rises_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        the_dark_knight_rises_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", oblivion_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        oblivion_name
    );
    assert_eq!(
        graph.vertex_by_key("people", jeanette_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        jeanette_name
    );
    assert_eq!(
        graph.vertex_by_key("people", morgan_freeman_name)
            .unwrap().unwrap()["age"].U8().unwrap(),
        80u8
    );

    let morgan_freeman =
        graph.vertex_by_key("people", morgan_freeman_name)
        .unwrap().unwrap();

    let batman_begins =
        graph.vertex_by_key("movie", batman_begins_name)
        .unwrap().unwrap();

    graph.link(&morgan_freeman, "acted-in", &batman_begins, Some(&data_map!{
        role: "Lucius Fox", works_for: "Bruce Wayne"
    })).unwrap().unwrap();
}
<commit_msg>a bit more test case<commit_after>use super::start_server;
use graph;
use graph::*;
use graph::edge::*;
use graph::vertex::*;
use server::schema::{MorpheusSchema, SchemaError, EMPTY_FIELDS};
use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Value, Map};
use neb::ram::cell::Cell;

#[test]
pub fn schemas() {
    let server = start_server(4001, "schemas");
    let graph = &server.graph;
    let mut edge_schema = MorpheusSchema::new(
        "test_edge_schema",
        None,
        &vec![Field::new(&"test_field", TypeId::U32 as u32, false, false, None)], false
    );
    assert_eq!(edge_schema.id, 0);
    assert!(
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new
            (
                graph::edge::EdgeType::Directed,
                false
            )).is_err());
    assert_eq!(edge_schema.id, 0);
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new(graph::edge::EdgeType::Directed, true)).unwrap();
    let mut vertex_schema = edge_schema.clone();
    vertex_schema.name = "test_vertex_schema".to_string();
    graph.new_vertex_group(&mut vertex_schema).unwrap();
    assert_eq!(edge_schema.id, 1);
    assert_eq!(vertex_schema.id, 2);
    let mut test_data = Map::new();
    test_data.insert("test_field", Value::U32(1));
    graph.new_vertex(&vertex_schema, test_data.clone()).unwrap();
    graph.new_vertex("test_edge_schema", test_data.clone()).is_err();
}

#[test]
pub fn relationship() {
    let server = start_server(4002, "relationship");
    let graph = &server.graph;
    let mut people_schema = MorpheusSchema::new("people", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None)
    ], true);
    let mut movie_schema = MorpheusSchema::new("movie", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None),
        Field::new("year", TypeId::U32 as u32, false, false, None)
    ], true);
    let mut acted_in_schema = MorpheusSchema::new("acted-in", None, &vec! [
        Field::new("role", TypeId::String as u32, false, false, None)
    ], true);
    let mut spouse_schema = MorpheusSchema::new("spouse", None, &EMPTY_FIELDS, false);
    graph.new_vertex_group(&mut people_schema).unwrap();
    graph.new_vertex_group(&mut movie_schema).unwrap();
    graph.new_edge_group(
        &mut acted_in_schema,
        EdgeAttributes::new(
            EdgeType::Directed,
            true
        )
    ).unwrap();
    graph.new_edge_group(
        &mut spouse_schema,
        EdgeAttributes::new(
            EdgeType::Undirected,
            false
        )
    ).unwrap();
    assert_eq!(people_schema.id, 1);
    assert_eq!(movie_schema.id, 2);
    assert_eq!(acted_in_schema.id, 3);
    assert_eq!(spouse_schema.id, 4);
    let morgan_freeman_name = "Morgan Freeman";
    let batman_begins_name = "Batman Begins";
    let the_dark_knight_name = "The Dark Knight";
    let the_dark_knight_rises_name = "The Dark Knight Rises";
    let oblivion_name = "Oblivion";
    let jeanette_name = "Jeanette Adair Bradshaw";
    graph.new_vertex("people", data_map!{
        name: morgan_freeman_name, age: 80 as u8
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: batman_begins_name, year: 2005 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: the_dark_knight_name, year: 2008 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: the_dark_knight_rises_name, year: 2012 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: oblivion_name, year: 2010 as u32
    }).unwrap();
    graph.new_vertex("people", data_map!{
        name: jeanette_name
    }).unwrap();

    assert_eq!(
        graph.vertex_by_key("people", morgan_freeman_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        morgan_freeman_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", batman_begins_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        batman_begins_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", the_dark_knight_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        the_dark_knight_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", the_dark_knight_rises_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        the_dark_knight_rises_name
    );
    assert_eq!(
        graph.vertex_by_key("movie", oblivion_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        oblivion_name
    );
    assert_eq!(
        graph.vertex_by_key("people", jeanette_name)
            .unwrap().unwrap()["name"].String().unwrap(),
        jeanette_name
    );
    assert_eq!(
        graph.vertex_by_key("people", morgan_freeman_name)
            .unwrap().unwrap()["age"].U8().unwrap(),
        80u8
    );

    let morgan_freeman =
        graph.vertex_by_key("people", morgan_freeman_name)
        .unwrap().unwrap();

    let batman_begins =
        graph.vertex_by_key("movie", batman_begins_name)
        .unwrap().unwrap();

    let the_dark_knight =
        graph.vertex_by_key("movie", the_dark_knight_name)
            .unwrap().unwrap();

    let the_dark_knight_rises =
        graph.vertex_by_key("movie", the_dark_knight_rises_name)
        .unwrap().unwrap();

    let oblivion =
        graph.vertex_by_key("movie", oblivion_name)
            .unwrap().unwrap();

    graph.link(&morgan_freeman, "acted-in", &batman_begins, Some(&data_map!{
        role: "Lucius Fox", works_for: "Bruce Wayne"
    })).unwrap().unwrap();
    graph.link(&morgan_freeman, "acted-in", &the_dark_knight, Some(&data_map!{
        role: "Lucius Fox"
    })).unwrap().unwrap();
    graph.link(&morgan_freeman, "acted-in", &the_dark_knight_rises, Some(&data_map!{
        role: "Lucius Fox"
    })).unwrap().unwrap();
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Main menu")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);

            // TODO: Button.
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
    NEW_GAME_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<commit_msg>Comment has been removed<commit_after>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Main menu")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
    NEW_GAME_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<|endoftext|>


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

#![feature(append)]
#![feature(bit_vec_append_split_off)]
#![feature(bitset)]
#![feature(bitvec)]
#![feature(box_syntax)]
#![feature(btree_range)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(const_fn)]
#![feature(core)]
#![feature(deque_extras)]
#![feature(drain)]
#![feature(enumset)]
#![feature(hash_default)]
#![feature(into_cow)]
#![feature(iter_idx)]
#![feature(iter_order)]
#![feature(iter_arith)]
#![feature(iter_to_vec)]
#![feature(map_in_place)]
#![feature(move_from)]
#![feature(num_bits_bytes)]
#![feature(pattern)]
#![feature(permutations)]
#![feature(rand)]
#![feature(range_inclusive)]
#![feature(rustc_private)]
#![feature(slice_bytes)]
#![feature(slice_chars)]
#![feature(slice_extras)]
#![feature(slice_position_elem)]
#![feature(split_off)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(str_escape)]
#![feature(str_match_indices)]
#![feature(str_utf16)]
#![feature(subslice_offset)]
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(vec_deque_retain)]
#![feature(vec_from_raw_buf)]
#![feature(vec_push_all)]
#![feature(vec_split_off)]
#![feature(vecmap)]

#[macro_use] extern crate log;

extern crate collections;
extern crate test;
extern crate rustc_unicode;

#[cfg(test)] #[macro_use] mod bench;

mod binary_heap;
mod bit;
mod btree;
mod enum_set;
mod fmt;
mod linked_list;
mod slice;
mod str;
mod string;
mod vec_deque;
mod vec_map;
mod vec;
<commit_msg>Auto merge of #26539 - jooert:remove_bit_vec_append_splitoff, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(append)]
#![feature(bitset)]
#![feature(bitvec)]
#![feature(box_syntax)]
#![feature(btree_range)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(const_fn)]
#![feature(core)]
#![feature(deque_extras)]
#![feature(drain)]
#![feature(enumset)]
#![feature(hash_default)]
#![feature(into_cow)]
#![feature(iter_idx)]
#![feature(iter_order)]
#![feature(iter_arith)]
#![feature(iter_to_vec)]
#![feature(map_in_place)]
#![feature(move_from)]
#![feature(num_bits_bytes)]
#![feature(pattern)]
#![feature(permutations)]
#![feature(rand)]
#![feature(range_inclusive)]
#![feature(rustc_private)]
#![feature(slice_bytes)]
#![feature(slice_chars)]
#![feature(slice_extras)]
#![feature(slice_position_elem)]
#![feature(split_off)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(str_escape)]
#![feature(str_match_indices)]
#![feature(str_utf16)]
#![feature(subslice_offset)]
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(vec_deque_retain)]
#![feature(vec_from_raw_buf)]
#![feature(vec_push_all)]
#![feature(vec_split_off)]
#![feature(vecmap)]

#[macro_use] extern crate log;

extern crate collections;
extern crate test;
extern crate rustc_unicode;

#[cfg(test)] #[macro_use] mod bench;

mod binary_heap;
mod bit;
mod btree;
mod enum_set;
mod fmt;
mod linked_list;
mod slice;
mod str;
mod string;
mod vec_deque;
mod vec_map;
mod vec;
<|endoftext|>


<commit_before>extern "C" {
    #[no_mangle]
    fn mmap_read8(addr: u32) -> i32;
    #[no_mangle]
    fn mmap_read16(addr: u32) -> i32;
    #[no_mangle]
    fn mmap_read32(addr: u32) -> i32;

    #[no_mangle]
    pub fn mmap_write8(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write16(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write32(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write64(addr: u32, v0: i32, v1: i32);
    #[no_mangle]
    pub fn mmap_write128(addr: u32, v0: i32, v1: i32, v2: i32, v3: i32);
}

use cpu2::cpu::*;
use cpu2::global_pointers::*;
use page::Page;
use std::ptr;

#[no_mangle]
pub fn in_mapped_range(addr: u32) -> bool {
    return addr >= 0xA0000 && addr < 0xC0000 || addr >= unsafe { *memory_size };
}

#[no_mangle]
pub fn read8(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read8(addr) };
    }
    else {
        return read8_no_mmap_check(addr);
    };
}
pub fn read8_no_mmap_check(addr: u32) -> i32 { unsafe { *mem8.offset(addr as isize) as i32 } }

#[no_mangle]
pub fn read16(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read16(addr) };
    }
    else {
        return read16_no_mmap_check(addr);
    };
}
pub fn read16_no_mmap_check(addr: u32) -> i32 {
    unsafe { *(mem8.offset(addr as isize) as *mut u16) as i32 }
}

#[no_mangle]
pub fn read32s(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read32(addr) };
    }
    else {
        return read32_no_mmap_check(addr);
    };
}
pub fn read32_no_mmap_check(addr: u32) -> i32 {
    unsafe { *(mem8.offset(addr as isize) as *mut i32) }
}

#[no_mangle]
pub unsafe fn read64s(addr: u32) -> i64 {
    if in_mapped_range(addr) {
        return mmap_read32(addr) as i64 | (mmap_read32(addr.wrapping_add(4 as u32)) as i64) << 32;
    }
    else {
        return *(mem8.offset(addr as isize) as *mut i64);
    };
}

#[no_mangle]
pub unsafe fn read_aligned32(addr: u32) -> i32 {
    dbg_assert!(addr < 0x40000000 as u32);
    if in_mapped_range(addr << 2) {
        return mmap_read32(addr << 2);
    }
    else {
        return *(mem8 as *mut i32).offset(addr as isize);
    };
}

#[no_mangle]
pub unsafe fn read128(addr: u32) -> reg128 {
    let mut value: reg128 = reg128 {
        i8_0: [0 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    };
    if in_mapped_range(addr) {
        value.i32_0[0] = mmap_read32(addr);
        value.i32_0[1] = mmap_read32(addr.wrapping_add(4 as u32));
        value.i32_0[2] = mmap_read32(addr.wrapping_add(8 as u32));
        value.i32_0[3] = mmap_read32(addr.wrapping_add(12 as u32))
    }
    else {
        value.i64_0[0] = *(mem8.offset(addr as isize) as *mut i64);
        value.i64_0[1] = *(mem8.offset(addr as isize).offset(8) as *mut i64)
    }
    return value;
}

#[no_mangle]
pub unsafe fn write8(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write8(addr, value);
    }
    else {
        ::jit::jit_dirty_page(::jit::get_jit_state(), Page::page_of(addr));
        write8_no_mmap_or_dirty_check(addr, value);
    };
}

pub unsafe fn write8_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *mem8.offset(addr as isize) = value as u8
}

#[no_mangle]
pub unsafe fn write16(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write16(addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(2 as u32));
        write16_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write16_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8.offset(addr as isize) as *mut u16) = value as u16
}

#[no_mangle]
pub unsafe fn write32(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write32(addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(4 as u32));
        write32_no_mmap_or_dirty_check(addr, value);
    };
}

pub unsafe fn write32_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8.offset(addr as isize) as *mut i32) = value
}

pub unsafe fn write_aligned32_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8 as *mut i32).offset(addr as isize) = value
}

#[no_mangle]
pub unsafe fn write_aligned32(addr: u32, value: i32) {
    dbg_assert!(addr < 0x40000000 as u32);
    let phys_addr = addr << 2;
    if in_mapped_range(phys_addr) {
        mmap_write32(phys_addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(phys_addr, phys_addr.wrapping_add(4 as u32));
        write_aligned32_no_mmap_or_dirty_check(addr, value);
    };
}

#[no_mangle]
pub unsafe fn write64(addr: u32, value: u64) {
    if in_mapped_range(addr) {
        mmap_write64(addr, value as i32, (value >> 32) as i32);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(8 as u32));
        write64_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write64_no_mmap_or_dirty_check(addr: u32, value: u64) {
    *(mem8.offset(addr as isize) as *mut u64) = value
}

#[no_mangle]
pub unsafe fn write128(addr: u32, value: reg128) {
    if in_mapped_range(addr) {
        mmap_write128(
            addr,
            value.i32_0[0],
            value.i32_0[1],
            value.i32_0[2],
            value.i32_0[3],
        );
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(16 as u32));
        write128_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write128_no_mmap_or_dirty_check(addr: u32, value: reg128) {
    *(mem8.offset(addr as isize) as *mut reg128) = value
}

pub unsafe fn memset_no_mmap_or_dirty_check(addr: u32, value: u8, count: u32) {
    ptr::write_bytes(mem8.offset(addr as isize), value, count as usize);
}

pub unsafe fn memcpy_no_mmap_or_dirty_check(src_addr: u32, dst_addr: u32, count: u32) {
    dbg_assert!(u32::max(src_addr, dst_addr) - u32::min(src_addr, dst_addr) >= count);
    ptr::copy_nonoverlapping(
        mem8.offset(src_addr as isize),
        mem8.offset(dst_addr as isize),
        count as usize,
    )
}
<commit_msg>Avoid use cpu2::cpu::* in memory<commit_after>extern "C" {
    #[no_mangle]
    fn mmap_read8(addr: u32) -> i32;
    #[no_mangle]
    fn mmap_read16(addr: u32) -> i32;
    #[no_mangle]
    fn mmap_read32(addr: u32) -> i32;

    #[no_mangle]
    pub fn mmap_write8(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write16(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write32(addr: u32, value: i32);
    #[no_mangle]
    pub fn mmap_write64(addr: u32, v0: i32, v1: i32);
    #[no_mangle]
    pub fn mmap_write128(addr: u32, v0: i32, v1: i32, v2: i32, v3: i32);
}

use cpu2::cpu::{mem8, reg128};
use cpu2::global_pointers::memory_size;
use page::Page;
use std::ptr;

#[no_mangle]
pub fn in_mapped_range(addr: u32) -> bool {
    return addr >= 0xA0000 && addr < 0xC0000 || addr >= unsafe { *memory_size };
}

#[no_mangle]
pub fn read8(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read8(addr) };
    }
    else {
        return read8_no_mmap_check(addr);
    };
}
pub fn read8_no_mmap_check(addr: u32) -> i32 { unsafe { *mem8.offset(addr as isize) as i32 } }

#[no_mangle]
pub fn read16(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read16(addr) };
    }
    else {
        return read16_no_mmap_check(addr);
    };
}
pub fn read16_no_mmap_check(addr: u32) -> i32 {
    unsafe { *(mem8.offset(addr as isize) as *mut u16) as i32 }
}

#[no_mangle]
pub fn read32s(addr: u32) -> i32 {
    if in_mapped_range(addr) {
        return unsafe { mmap_read32(addr) };
    }
    else {
        return read32_no_mmap_check(addr);
    };
}
pub fn read32_no_mmap_check(addr: u32) -> i32 {
    unsafe { *(mem8.offset(addr as isize) as *mut i32) }
}

#[no_mangle]
pub unsafe fn read64s(addr: u32) -> i64 {
    if in_mapped_range(addr) {
        return mmap_read32(addr) as i64 | (mmap_read32(addr.wrapping_add(4 as u32)) as i64) << 32;
    }
    else {
        return *(mem8.offset(addr as isize) as *mut i64);
    };
}

#[no_mangle]
pub unsafe fn read_aligned32(addr: u32) -> i32 {
    dbg_assert!(addr < 0x40000000 as u32);
    if in_mapped_range(addr << 2) {
        return mmap_read32(addr << 2);
    }
    else {
        return *(mem8 as *mut i32).offset(addr as isize);
    };
}

#[no_mangle]
pub unsafe fn read128(addr: u32) -> reg128 {
    let mut value: reg128 = reg128 {
        i8_0: [0 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    };
    if in_mapped_range(addr) {
        value.i32_0[0] = mmap_read32(addr);
        value.i32_0[1] = mmap_read32(addr.wrapping_add(4 as u32));
        value.i32_0[2] = mmap_read32(addr.wrapping_add(8 as u32));
        value.i32_0[3] = mmap_read32(addr.wrapping_add(12 as u32))
    }
    else {
        value.i64_0[0] = *(mem8.offset(addr as isize) as *mut i64);
        value.i64_0[1] = *(mem8.offset(addr as isize).offset(8) as *mut i64)
    }
    return value;
}

#[no_mangle]
pub unsafe fn write8(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write8(addr, value);
    }
    else {
        ::jit::jit_dirty_page(::jit::get_jit_state(), Page::page_of(addr));
        write8_no_mmap_or_dirty_check(addr, value);
    };
}

pub unsafe fn write8_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *mem8.offset(addr as isize) = value as u8
}

#[no_mangle]
pub unsafe fn write16(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write16(addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(2 as u32));
        write16_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write16_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8.offset(addr as isize) as *mut u16) = value as u16
}

#[no_mangle]
pub unsafe fn write32(addr: u32, value: i32) {
    if in_mapped_range(addr) {
        mmap_write32(addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(4 as u32));
        write32_no_mmap_or_dirty_check(addr, value);
    };
}

pub unsafe fn write32_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8.offset(addr as isize) as *mut i32) = value
}

pub unsafe fn write_aligned32_no_mmap_or_dirty_check(addr: u32, value: i32) {
    *(mem8 as *mut i32).offset(addr as isize) = value
}

#[no_mangle]
pub unsafe fn write_aligned32(addr: u32, value: i32) {
    dbg_assert!(addr < 0x40000000 as u32);
    let phys_addr = addr << 2;
    if in_mapped_range(phys_addr) {
        mmap_write32(phys_addr, value);
    }
    else {
        ::jit::jit_dirty_cache_small(phys_addr, phys_addr.wrapping_add(4 as u32));
        write_aligned32_no_mmap_or_dirty_check(addr, value);
    };
}

#[no_mangle]
pub unsafe fn write64(addr: u32, value: u64) {
    if in_mapped_range(addr) {
        mmap_write64(addr, value as i32, (value >> 32) as i32);
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(8 as u32));
        write64_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write64_no_mmap_or_dirty_check(addr: u32, value: u64) {
    *(mem8.offset(addr as isize) as *mut u64) = value
}

#[no_mangle]
pub unsafe fn write128(addr: u32, value: reg128) {
    if in_mapped_range(addr) {
        mmap_write128(
            addr,
            value.i32_0[0],
            value.i32_0[1],
            value.i32_0[2],
            value.i32_0[3],
        );
    }
    else {
        ::jit::jit_dirty_cache_small(addr, addr.wrapping_add(16 as u32));
        write128_no_mmap_or_dirty_check(addr, value);
    };
}
pub unsafe fn write128_no_mmap_or_dirty_check(addr: u32, value: reg128) {
    *(mem8.offset(addr as isize) as *mut reg128) = value
}

pub unsafe fn memset_no_mmap_or_dirty_check(addr: u32, value: u8, count: u32) {
    ptr::write_bytes(mem8.offset(addr as isize), value, count as usize);
}

pub unsafe fn memcpy_no_mmap_or_dirty_check(src_addr: u32, dst_addr: u32, count: u32) {
    dbg_assert!(u32::max(src_addr, dst_addr) - u32::min(src_addr, dst_addr) >= count);
    ptr::copy_nonoverlapping(
        mem8.offset(src_addr as isize),
        mem8.offset(dst_addr as isize),
        count as usize,
    )
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::{DerefMut, Deref};
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::num_cpus;
use super::socket::Socket;
use super::simple_stream::SimpleStream;

pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let mut sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Master id list
        // TODO - Figure out if this is needed to ensure collisions aren't made?
        let mut ids = Arc::new(Mutex::new(LinkedList::<u32>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        println!("efd: {}", epoll_instance);

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match SimpleStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let mut socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                        });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => {},
                        Err(e) => println!("Epoll CtrlError: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        err_tx.send(());
    }

    ///
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        events.set_len(100);

        println!("epd: {}", epoll_instance);

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        EventLoop::handle_epoll_event(tx_clone, &events[x as usize], s_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// SimpleStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the SimpleStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(uspace_tx: Sender<EventTuple>,
                          event: &EpollEvent,
                          sockets: SocketList) {

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        for msg in socket.buffer().iter() {
                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        // TODO - Figure out how to handle
                    }
                }
            }
        }
    }
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::{DerefMut, Deref};
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::num_cpus;
use super::socket::Socket;
use super::simple_stream::SimpleStream;

pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let mut sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Master id list
        // TODO - Figure out if this is needed to ensure collisions aren't made?
        let mut ids = Arc::new(Mutex::new(LinkedList::<u32>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        println!("efd: {}", epoll_instance);

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match SimpleStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let mut socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                        });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => {},
                        Err(e) => println!("Epoll CtrlError: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        err_tx.send(());
    }

    ///
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        unsafe { events.set_len(100); }

        println!("epd: {}", epoll_instance);

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        EventLoop::handle_epoll_event(tx_clone, &events[x as usize], s_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// SimpleStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the SimpleStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(uspace_tx: Sender<EventTuple>,
                          event: &EpollEvent,
                          sockets: SocketList) {

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        for msg in socket.buffer().iter() {
                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        // TODO - Figure out how to handle
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 Johannes Köster, Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment algorithms.

pub mod pairwise;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

/// An alignment, consisting of a score, a start in sequence y, a start in sequence x, a length
/// and its edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }
        else {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    pub fn pretty(&self, x: &[u8], y: &[u8]) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i : usize = self.xstart;
            let mut y_i : usize = self.ystart;

            // Add '-' before aligned subsequences and un-aligned 5' substrings of sequences.
            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            } else {
                for i in 0..x_i {
                    x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
                    y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
                }
            }
            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            // Process the alignment.
            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    },
                }
            }

            // Add un-aligned 3' substrings of sequences.
            for i in x_i..x.len() {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
            }
            for i in y_i..y.len() {
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
            }

            // Add trailing '-'.
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }

    #[test]
    fn test_pretty_alignment() {
        let y = b"TACCGTGGAC";
        let x = b"AAAAACCGTTGACGCAA";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        // alignment.operations: [Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        // let mut alignment = align_semiglobal!(x, y, -5, -1, score);
        // assert_eq!(alignment.pretty(x, y), align_semiglobal_pretty!(x, y, -5, -1, score));
        println!("semiglobal:\t{:?}", alignment);
        println!("SEMIGLOBAL: \n{}\n", alignment.pretty(x, y));
        // alignment.operations: [Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        // alignment = align_local!(x, y, -5, -1, score);
        let alignment = aligner.local(x, y);
        println!("local:\t{:?}", alignment);
        println!("LOCAL: \n{}\n", alignment.pretty(x, y));
        // assert_eq!(alignment.pretty(x, y), align_local_pretty!(x, y, -5, -1, score));
        // alignment.operations: [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        // alignment = align_global!(x, y, -5, -1, score);
        let alignment = aligner.global(x, y);
        println!("global:\t{:?}", alignment);
        println!("GLOBAL: \n{}\n", alignment.pretty(x, y));

        // let x = b"AAAAAAA";
        // let y = b"TTTTTTTTTT";
        // let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        // let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        // let alignment = aligner.semiglobal(x, y);
        // println!("SEMIGLOBAL: \n{}\n", alignment.pretty(x, y));
        // let alignment = aligner.local(x, y);
        // println!("LOCAL: \n{}\n", alignment.pretty(x, y));
        // let alignment = aligner.global(x, y);
        // println!("GLOBAL: \n{}\n", alignment.pretty(x, y));
        // assert_eq!(alignment.pretty(x, y), align_global_pretty!(x, y, -5, -1, score));
    }

    // fn test_pretty_alignment() {
    //     let x = b"TACCGTGGAC";
    //     let y = b"AAAAACCGTTGACGCAA";
    //     let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
    //     let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
    //     let alignment = aligner.semiglobal(x, y);
    //     let alignment = aligner.local(x, y);
    //     let alignment = aligner.global(x, y);
    // }
}
<commit_msg>add pub mod distance<commit_after>// Copyright 2014-2015 Johannes Köster, Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment algorithms.

pub mod pairwise;
pub mod distance;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

/// An alignment, consisting of a score, a start in sequence y, a start in sequence x, a length
/// and its edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }
        else {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    pub fn pretty(&self, x: &[u8], y: &[u8]) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i : usize = self.xstart;
            let mut y_i : usize = self.ystart;

            // Add '-' before aligned subsequences and un-aligned 5' substrings of sequences.
            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            } else {
                for i in 0..x_i {
                    x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
                    y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
                }
            }
            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            // Process the alignment.
            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    },
                }
            }

            // Add un-aligned 3' substrings of sequences.
            for i in x_i..x.len() {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
            }
            for i in y_i..y.len() {
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
            }

            // Add trailing '-'.
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }

    #[test]
    fn test_pretty_alignment() {
        let y = b"TACCGTGGAC";
        let x = b"AAAAACCGTTGACGCAA";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        // alignment.operations: [Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        // let mut alignment = align_semiglobal!(x, y, -5, -1, score);
        // assert_eq!(alignment.pretty(x, y), align_semiglobal_pretty!(x, y, -5, -1, score));
        println!("semiglobal:\t{:?}", alignment);
        println!("SEMIGLOBAL: \n{}\n", alignment.pretty(x, y));
        // alignment.operations: [Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        // alignment = align_local!(x, y, -5, -1, score);
        let alignment = aligner.local(x, y);
        println!("local:\t{:?}", alignment);
        println!("LOCAL: \n{}\n", alignment.pretty(x, y));
        // assert_eq!(alignment.pretty(x, y), align_local_pretty!(x, y, -5, -1, score));
        // alignment.operations: [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]
        // alignment = align_global!(x, y, -5, -1, score);
        let alignment = aligner.global(x, y);
        println!("global:\t{:?}", alignment);
        println!("GLOBAL: \n{}\n", alignment.pretty(x, y));

        // let x = b"AAAAAAA";
        // let y = b"TTTTTTTTTT";
        // let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        // let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        // let alignment = aligner.semiglobal(x, y);
        // println!("SEMIGLOBAL: \n{}\n", alignment.pretty(x, y));
        // let alignment = aligner.local(x, y);
        // println!("LOCAL: \n{}\n", alignment.pretty(x, y));
        // let alignment = aligner.global(x, y);
        // println!("GLOBAL: \n{}\n", alignment.pretty(x, y));
        // assert_eq!(alignment.pretty(x, y), align_global_pretty!(x, y, -5, -1, score));
    }

    // fn test_pretty_alignment() {
    //     let x = b"TACCGTGGAC";
    //     let y = b"AAAAACCGTTGACGCAA";
    //     let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
    //     let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
    //     let alignment = aligner.semiglobal(x, y);
    //     let alignment = aligner.local(x, y);
    //     let alignment = aligner.global(x, y);
    // }
}
<|endoftext|>