<commit_before>use rocket::response::{Response, Responder};
use rocket::{self, State};
use rocket_contrib::Json;
use rocket::request::{self, FromRequest, Request};
use rocket::Outcome;
use rocket::http::{Status, Cookie, Cookies};
use adapters::json;
use adapters::user_communication;
use entities::*;
use business::db::Db;
use business::error::{Error, RepoError, ParameterError};
use infrastructure::error::AppError;
use serde_json::ser::to_string;
use business::{usecase, geo};
use business::duplicates::{self, DuplicateType};
use std::result;
use super::util;

#[cfg(all(not(test), feature = "sqlite"))]
use super::sqlite;

#[cfg(all(not(test), feature = "sqlite"))]
type DbPool = sqlite::ConnectionPool;

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

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

const COOKIE_USER_KEY: &str = "user_id";

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

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

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

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

fn get_search_inner(db: &DbPool, search: SearchQuery) -> Result<json::SearchResponse> {

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

    let categories = match search.categories {
        Some(cat_str) => Some(util::extract_ids(&cat_str)),
        None => None,
    };

    let mut tags = vec![];

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

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

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

    let avg_ratings = match super::ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };

    let req = usecase::SearchRequest {
        bbox,
        categories,
        text,
        tags,
        entry_ratings: &*avg_ratings,
    };

    let (visible, invisible) = usecase::search(&mut *db.get()?, req)?;

    let visible = visible
        .into_iter()
        .map(|e| {
            json::EntryIdWithCoordinates {
                id: e.id,
                lat: e.lat,
                lng: e.lng,
            }
        })
        .collect();

    let invisible = invisible
        .into_iter()
        .map(|e| {
            json::EntryIdWithCoordinates {
                id: e.id,
                lat: e.lat,
                lng: e.lng,
            }
        })
        .collect();

    Ok(Json(json::SearchResponse { visible, invisible }))
}

#[derive(Deserialize, Debug, Clone)]
struct Login(String);

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: State<DbPool>, ids: String) -> Result<Vec<json::Entry>> {
    let ids = util::extract_ids(&ids);
    let entries = usecase::get_entries(&*db.get()?, &ids)?;
    let ratings = usecase::get_ratings_by_entry_ids(&*db.get()?, &ids)?;
    Ok(Json(
        entries
            .into_iter()
            .map(|e| {
                let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
                json::Entry::from_entry_with_ratings(e, 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))
}

#[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> {
    Ok(Json(db.get()?.all_tags()?.len()))
}

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

#[post("/users", format = "application/json", data = "<u>")]
fn post_user(db: State<DbPool>, u: Json<usecase::NewUser>) -> Result<()> {
    let new_user = u.into_inner();
    usecase::create_new_user(&mut *db.get()?, new_user.clone())?;
    let user = db.get()?.get_user(&new_user.username)?;
    let subject = "Karte von Morgen: bitte bestätige deine Email-Adresse";
    let body = user_communication::email_confirmation_email(&user.id);
    util::send_mails(vec![user.email.clone()], &subject, &body);
    Ok(Json(()))
}

#[delete("/users/<u_id>")]
fn delete_user(db: State<DbPool>, user: Login, u_id: String) -> Result<()> {
    usecase::delete_user(&mut *db.get()?, &user.0, &u_id)?;
    Ok(Json(()))
}

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

#[get("/ratings/<id>")]
fn get_ratings(db: State<DbPool>, id: String) -> Result<Vec<json::Rating>> {
    let ratings = usecase::get_ratings(&*db.get()?, &util::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))
}

#[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(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(user: Json<UserId>, db: State<DbPool>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    let u = db.get()?.confirm_email_address(&u_id)?;
    if u.id == u_id {
        Ok(Json(()))
    } else {
        Err(AppError::Business(Error::Repo(RepoError::NotFound)))
    }
}

#[post("/subscribe-to-bbox", format = "application/json", data = "<coordinates>")]
fn subscribe_to_bbox(
    user: Login,
    coordinates: Json<Vec<Coordinate>>,
    db: State<DbPool>,
) -> Result<()> {
    let coordinates = coordinates.into_inner();
    let Login(username) = user;
    usecase::subscribe_to_bbox(&coordinates, &username, &mut *db.get()?)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(user: Login, db: State<DbPool>) -> Result<()> {
    let Login(username) = user;
    usecase::unsubscribe_all_bboxes_by_username(&mut *db.get()?, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(db: State<DbPool>, user: Login) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecase::get_bbox_subscriptions(&username, &*db.get()?)?
        .into_iter()
        .map(|s| {
            json::BboxSubscription {
                id: s.id,
                south_west_lat: s.bbox.south_west.lat,
                south_west_lng: s.bbox.south_west.lng,
                north_east_lat: s.bbox.north_east.lat,
                north_east_lng: s.bbox.north_east.lng,
            }
        })
        .collect();
    Ok(Json(user_subscriptions))
}

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

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(db: State<DbPool>, e: Json<usecase::NewEntry>) -> Result<String> {
    let e = e.into_inner();
    let id = usecase::create_new_entry(&mut *db.get()?, e.clone())?;
    let email_addresses = usecase::email_addresses_by_coordinate(&mut *db.get()?, &e.lat, &e.lng)?;
    let all_categories = db.get()?.all_categories()?;
    util::notify_create_entry(email_addresses, &e, &id, all_categories);
    Ok(Json(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())?;
    let email_addresses = usecase::email_addresses_by_coordinate(&mut *db.get()?, &e.lat, &e.lng)?;
    let all_categories = db.get()?.all_categories()?;
    util::notify_update_entry(email_addresses, &e, all_categories);
    Ok(Json(id))
}

#[get("/tags")]
fn get_tags(db: State<DbPool>) -> Result<Vec<String>> {
    Ok(Json(
        db.get()?.all_tags()?.into_iter().map(|t| t.id).collect(),
    ))
}

#[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 = util::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))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials => Status::Unauthorized,
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        _ => Status::BadRequest,
                    })
                }
                Error::Repo(ref err) => {
                    match *err {
                        RepoError::NotFound => return Err(Status::NotFound),
                        _ => {}
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use super::super::mockdb;
    use super::super::{calculate_all_ratings, ENTRY_RATINGS};

    fn setup() -> mockdb::ConnectionPool {
        mockdb::create_connection_pool(":memory:").unwrap()
    }

    #[bench]
    fn bench_search_in_10_000_rated_entries(b: &mut Bencher) {
        let (entries, ratings) = ::business::sort::tests::create_entries_with_ratings(10_000);
        let pool = setup();
        pool.get().unwrap().entries = entries;
        pool.get().unwrap().ratings = ratings;
        calculate_all_ratings(&*pool.get().unwrap()).unwrap();
        assert_eq!((*ENTRY_RATINGS.lock().unwrap()).len(),10_000);
        let query = super::SearchQuery {
            bbox: "-10,-10,10,10".into(),
            categories: None,
            text: None,
            tags: None,
        };
        b.iter(|| super::get_search_inner(&pool, query.clone()).unwrap());
    }
}
<commit_msg>fix(test): assert that there a many rating<commit_after>use rocket::response::{Response, Responder};
use rocket::{self, State};
use rocket_contrib::Json;
use rocket::request::{self, FromRequest, Request};
use rocket::Outcome;
use rocket::http::{Status, Cookie, Cookies};
use adapters::json;
use adapters::user_communication;
use entities::*;
use business::db::Db;
use business::error::{Error, RepoError, ParameterError};
use infrastructure::error::AppError;
use serde_json::ser::to_string;
use business::{usecase, geo};
use business::duplicates::{self, DuplicateType};
use std::result;
use super::util;

#[cfg(all(not(test), feature = "sqlite"))]
use super::sqlite;

#[cfg(all(not(test), feature = "sqlite"))]
type DbPool = sqlite::ConnectionPool;

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

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

const COOKIE_USER_KEY: &str = "user_id";

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

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

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

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

fn get_search_inner(db: &DbPool, search: SearchQuery) -> Result<json::SearchResponse> {

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

    let categories = match search.categories {
        Some(cat_str) => Some(util::extract_ids(&cat_str)),
        None => None,
    };

    let mut tags = vec![];

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

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

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

    let avg_ratings = match super::ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };

    let req = usecase::SearchRequest {
        bbox,
        categories,
        text,
        tags,
        entry_ratings: &*avg_ratings,
    };

    let (visible, invisible) = usecase::search(&mut *db.get()?, req)?;

    let visible = visible
        .into_iter()
        .map(|e| {
            json::EntryIdWithCoordinates {
                id: e.id,
                lat: e.lat,
                lng: e.lng,
            }
        })
        .collect();

    let invisible = invisible
        .into_iter()
        .map(|e| {
            json::EntryIdWithCoordinates {
                id: e.id,
                lat: e.lat,
                lng: e.lng,
            }
        })
        .collect();

    Ok(Json(json::SearchResponse { visible, invisible }))
}

#[derive(Deserialize, Debug, Clone)]
struct Login(String);

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: State<DbPool>, ids: String) -> Result<Vec<json::Entry>> {
    let ids = util::extract_ids(&ids);
    let entries = usecase::get_entries(&*db.get()?, &ids)?;
    let ratings = usecase::get_ratings_by_entry_ids(&*db.get()?, &ids)?;
    Ok(Json(
        entries
            .into_iter()
            .map(|e| {
                let r = ratings.get(&e.id).cloned().unwrap_or_else(|| vec![]);
                json::Entry::from_entry_with_ratings(e, 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))
}

#[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> {
    Ok(Json(db.get()?.all_tags()?.len()))
}

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

#[post("/users", format = "application/json", data = "<u>")]
fn post_user(db: State<DbPool>, u: Json<usecase::NewUser>) -> Result<()> {
    let new_user = u.into_inner();
    usecase::create_new_user(&mut *db.get()?, new_user.clone())?;
    let user = db.get()?.get_user(&new_user.username)?;
    let subject = "Karte von Morgen: bitte bestätige deine Email-Adresse";
    let body = user_communication::email_confirmation_email(&user.id);
    util::send_mails(vec![user.email.clone()], &subject, &body);
    Ok(Json(()))
}

#[delete("/users/<u_id>")]
fn delete_user(db: State<DbPool>, user: Login, u_id: String) -> Result<()> {
    usecase::delete_user(&mut *db.get()?, &user.0, &u_id)?;
    Ok(Json(()))
}

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

#[get("/ratings/<id>")]
fn get_ratings(db: State<DbPool>, id: String) -> Result<Vec<json::Rating>> {
    let ratings = usecase::get_ratings(&*db.get()?, &util::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))
}

#[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(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(user: Json<UserId>, db: State<DbPool>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    let u = db.get()?.confirm_email_address(&u_id)?;
    if u.id == u_id {
        Ok(Json(()))
    } else {
        Err(AppError::Business(Error::Repo(RepoError::NotFound)))
    }
}

#[post("/subscribe-to-bbox", format = "application/json", data = "<coordinates>")]
fn subscribe_to_bbox(
    user: Login,
    coordinates: Json<Vec<Coordinate>>,
    db: State<DbPool>,
) -> Result<()> {
    let coordinates = coordinates.into_inner();
    let Login(username) = user;
    usecase::subscribe_to_bbox(&coordinates, &username, &mut *db.get()?)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(user: Login, db: State<DbPool>) -> Result<()> {
    let Login(username) = user;
    usecase::unsubscribe_all_bboxes_by_username(&mut *db.get()?, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(db: State<DbPool>, user: Login) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecase::get_bbox_subscriptions(&username, &*db.get()?)?
        .into_iter()
        .map(|s| {
            json::BboxSubscription {
                id: s.id,
                south_west_lat: s.bbox.south_west.lat,
                south_west_lng: s.bbox.south_west.lng,
                north_east_lat: s.bbox.north_east.lat,
                north_east_lng: s.bbox.north_east.lng,
            }
        })
        .collect();
    Ok(Json(user_subscriptions))
}

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

#[post("/entries", format = "application/json", data = "<e>")]
fn post_entry(db: State<DbPool>, e: Json<usecase::NewEntry>) -> Result<String> {
    let e = e.into_inner();
    let id = usecase::create_new_entry(&mut *db.get()?, e.clone())?;
    let email_addresses = usecase::email_addresses_by_coordinate(&mut *db.get()?, &e.lat, &e.lng)?;
    let all_categories = db.get()?.all_categories()?;
    util::notify_create_entry(email_addresses, &e, &id, all_categories);
    Ok(Json(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())?;
    let email_addresses = usecase::email_addresses_by_coordinate(&mut *db.get()?, &e.lat, &e.lng)?;
    let all_categories = db.get()?.all_categories()?;
    util::notify_update_entry(email_addresses, &e, all_categories);
    Ok(Json(id))
}

#[get("/tags")]
fn get_tags(db: State<DbPool>) -> Result<Vec<String>> {
    Ok(Json(
        db.get()?.all_tags()?.into_iter().map(|t| t.id).collect(),
    ))
}

#[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 = util::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))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials => Status::Unauthorized,
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        _ => Status::BadRequest,
                    })
                }
                Error::Repo(ref err) => {
                    match *err {
                        RepoError::NotFound => return Err(Status::NotFound),
                        _ => {}
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use super::super::mockdb;
    use super::super::{calculate_all_ratings, ENTRY_RATINGS};

    fn setup() -> mockdb::ConnectionPool {
        mockdb::create_connection_pool(":memory:").unwrap()
    }

    #[bench]
    fn bench_search_in_10_000_rated_entries(b: &mut Bencher) {
        let (entries, ratings) = ::business::sort::tests::create_entries_with_ratings(10_000);
        let pool = setup();
        pool.get().unwrap().entries = entries;
        pool.get().unwrap().ratings = ratings;
        calculate_all_ratings(&*pool.get().unwrap()).unwrap();
        assert!((*ENTRY_RATINGS.lock().unwrap()).len() > 9_000);
        let query = super::SearchQuery {
            bbox: "-10,-10,10,10".into(),
            categories: None,
            text: None,
            tags: None,
        };
        b.iter(|| super::get_search_inner(&pool, query.clone()).unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use super::*;
use mktemp::Temp;
use std::path::PathBuf;

pub fn create_hook(path: PathBuf, contents: &str, mode: u32) {
    use std::fs::create_dir_all;
    use std::fs::metadata;
    use std::fs::File;
    use std::io::Write;
    use std::os::unix::fs::PermissionsExt;

    // ensure path exists
    create_dir_all(path.parent().unwrap()).unwrap();

    let mut file = File::create(&path).unwrap();
    file.write_all(contents.as_bytes()).unwrap();

    let mut permissions = metadata(path).unwrap().permissions();
    permissions.set_mode(mode);
    file.set_permissions(permissions).unwrap();
}

pub fn product_uid_hook(path: &Path) -> PathBuf {
    path.join(PRODUCT_UID_HOOK)
}

pub fn version_hook(path: &Path) -> PathBuf {
    path.join(VERSION_HOOK)
}

pub fn hardware_hook(path: &Path) -> PathBuf {
    path.join(HARDWARE_HOOK)
}

pub fn device_identity_dir(path: &Path) -> PathBuf {
    path.join(DEVICE_IDENTITY_DIR).join("identity")
}

pub fn device_attributes_dir(path: &Path) -> PathBuf {
    path.join(DEVICE_ATTRIBUTES_DIR).join("attributes")
}

pub enum FakeDevice {
    NoUpdate,
    HasUpdate,
    ExtraPoll,
    InvalidHardware,
}

pub fn create_fake_metadata(device: FakeDevice) -> PathBuf {
    let tmpdir = Temp::new_dir().unwrap().to_path_buf();

    // create fake hooks to be used to validate the load
    create_hook(
        product_uid_hook(&tmpdir),
        "#!/bin/sh\necho 229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
        0o755,
    );
    create_hook(version_hook(&tmpdir), "#!/bin/sh\necho 1.1", 0o755);
    create_hook(
        hardware_hook(&tmpdir),
        &format!(
            "#!/bin/sh\necho {}",
            match device {
                FakeDevice::InvalidHardware => "invalid",
                _ => "board",
            }
        ),
        0o755,
    );
    create_hook(
        device_identity_dir(&tmpdir),
        &format!(
            "#!/bin/sh\necho id1=value{}\necho id2=value2",
            match device {
                FakeDevice::NoUpdate => 1,
                FakeDevice::HasUpdate => 2,
                FakeDevice::ExtraPoll => 3,
                FakeDevice::InvalidHardware => 4,
            }
        ),
        0o755,
    );
    create_hook(
        device_attributes_dir(&tmpdir),
        "#!/bin/sh\necho attr1=attrvalue1\necho attr2=attrvalue2",
        0o755,
    );

    tmpdir
}

#[test]
fn run_multiple_hooks_in_a_dir() {
    let tmpdir = Temp::new_dir().unwrap();

    // create two scripts so we can test the parsing of output
    create_hook(
        tmpdir.to_path_buf().join("hook1"),
        "#!/bin/sh\necho key2=val2\necho key1=val1",
        0o755,
    );
    create_hook(
        tmpdir.to_path_buf().join("hook2"),
        "#!/bin/sh\necho key2=val4\necho key1=val3",
        0o755,
    );

    let fv = run_hooks_from_dir(&tmpdir.to_path_buf()).unwrap();

    assert_eq!(fv.keys().len(), 2);
    assert_eq!(fv.keys().collect::<Vec<_>>(), ["key1", "key2"]);
    assert_eq!(fv["key1"], ["val1", "val3"]);
    assert_eq!(fv["key2"], ["val2", "val4"]);
}

#[test]
fn check_load_metadata() {
    use std::fs::remove_file;

    {
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        // check error with a invalid product uid
        create_hook(
            product_uid_hook(&metadata_dir),
            "#!/bin/sh\necho 123",
            0o755,
        );
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check error when lacks product uid
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(product_uid_hook(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check error when lacks device identity
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(device_identity_dir(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check if is still valid without device attributes
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(device_attributes_dir(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir).unwrap();
        assert_eq!(
            "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            metadata.product_uid
        );
        assert_eq!("1.1", metadata.version);
        assert_eq!("board", metadata.hardware);
        assert_eq!(2, metadata.device_identity.len());
        assert_eq!(0, metadata.device_attributes.len());
    }

    {
        // complete metadata
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        let metadata = Metadata::new(&metadata_dir).unwrap();
        assert_eq!(
            "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            metadata.product_uid
        );
        assert_eq!("1.1", metadata.version);
        assert_eq!("board", metadata.hardware);
        assert_eq!(2, metadata.device_identity.len());
        assert_eq!(2, metadata.device_attributes.len());
    }
}
<commit_msg>firmware: tests: sleep 50ms when creating fake hooks<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use super::*;
use mktemp::Temp;
use std::path::PathBuf;

pub fn create_hook(path: PathBuf, contents: &str, mode: u32) {
    use std::fs::create_dir_all;
    use std::fs::metadata;
    use std::fs::File;
    use std::io::Write;
    use std::os::unix::fs::PermissionsExt;
    use std::{thread, time};

    // ensure path exists
    create_dir_all(path.parent().unwrap()).unwrap();

    let mut file = File::create(&path).unwrap();
    file.write_all(contents.as_bytes()).unwrap();

    let mut permissions = metadata(path).unwrap().permissions();
    permissions.set_mode(mode);
    file.set_permissions(permissions).unwrap();

    // This is needed because the filesystem may report it is complete
    // before it finishes writing it.
    thread::sleep(time::Duration::from_millis(50));
}

pub fn product_uid_hook(path: &Path) -> PathBuf {
    path.join(PRODUCT_UID_HOOK)
}

pub fn version_hook(path: &Path) -> PathBuf {
    path.join(VERSION_HOOK)
}

pub fn hardware_hook(path: &Path) -> PathBuf {
    path.join(HARDWARE_HOOK)
}

pub fn device_identity_dir(path: &Path) -> PathBuf {
    path.join(DEVICE_IDENTITY_DIR).join("identity")
}

pub fn device_attributes_dir(path: &Path) -> PathBuf {
    path.join(DEVICE_ATTRIBUTES_DIR).join("attributes")
}

pub enum FakeDevice {
    NoUpdate,
    HasUpdate,
    ExtraPoll,
    InvalidHardware,
}

pub fn create_fake_metadata(device: FakeDevice) -> PathBuf {
    let tmpdir = Temp::new_dir().unwrap().to_path_buf();

    // create fake hooks to be used to validate the load
    create_hook(
        product_uid_hook(&tmpdir),
        "#!/bin/sh\necho 229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
        0o755,
    );
    create_hook(version_hook(&tmpdir), "#!/bin/sh\necho 1.1", 0o755);
    create_hook(
        hardware_hook(&tmpdir),
        &format!(
            "#!/bin/sh\necho {}",
            match device {
                FakeDevice::InvalidHardware => "invalid",
                _ => "board",
            }
        ),
        0o755,
    );
    create_hook(
        device_identity_dir(&tmpdir),
        &format!(
            "#!/bin/sh\necho id1=value{}\necho id2=value2",
            match device {
                FakeDevice::NoUpdate => 1,
                FakeDevice::HasUpdate => 2,
                FakeDevice::ExtraPoll => 3,
                FakeDevice::InvalidHardware => 4,
            }
        ),
        0o755,
    );
    create_hook(
        device_attributes_dir(&tmpdir),
        "#!/bin/sh\necho attr1=attrvalue1\necho attr2=attrvalue2",
        0o755,
    );

    tmpdir
}

#[test]
fn run_multiple_hooks_in_a_dir() {
    let tmpdir = Temp::new_dir().unwrap();

    // create two scripts so we can test the parsing of output
    create_hook(
        tmpdir.to_path_buf().join("hook1"),
        "#!/bin/sh\necho key2=val2\necho key1=val1",
        0o755,
    );
    create_hook(
        tmpdir.to_path_buf().join("hook2"),
        "#!/bin/sh\necho key2=val4\necho key1=val3",
        0o755,
    );

    let fv = run_hooks_from_dir(&tmpdir.to_path_buf()).unwrap();

    assert_eq!(fv.keys().len(), 2);
    assert_eq!(fv.keys().collect::<Vec<_>>(), ["key1", "key2"]);
    assert_eq!(fv["key1"], ["val1", "val3"]);
    assert_eq!(fv["key2"], ["val2", "val4"]);
}

#[test]
fn check_load_metadata() {
    use std::fs::remove_file;

    {
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        // check error with a invalid product uid
        create_hook(
            product_uid_hook(&metadata_dir),
            "#!/bin/sh\necho 123",
            0o755,
        );
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check error when lacks product uid
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(product_uid_hook(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check error when lacks device identity
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(device_identity_dir(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir);
        assert!(metadata.is_err());
    }

    {
        // check if is still valid without device attributes
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        remove_file(device_attributes_dir(&metadata_dir)).unwrap();
        let metadata = Metadata::new(&metadata_dir).unwrap();
        assert_eq!(
            "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            metadata.product_uid
        );
        assert_eq!("1.1", metadata.version);
        assert_eq!("board", metadata.hardware);
        assert_eq!(2, metadata.device_identity.len());
        assert_eq!(0, metadata.device_attributes.len());
    }

    {
        // complete metadata
        let metadata_dir = create_fake_metadata(FakeDevice::NoUpdate);
        let metadata = Metadata::new(&metadata_dir).unwrap();
        assert_eq!(
            "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            metadata.product_uid
        );
        assert_eq!("1.1", metadata.version);
        assert_eq!("board", metadata.hardware);
        assert_eq!(2, metadata.device_identity.len());
        assert_eq!(2, metadata.device_attributes.len());
    }
}
<|endoftext|>


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

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0178: r##"
In types, the `+` type operator has low precedence, so it is often necessary
to use parentheses.

For example:

```compile_fail,E0178
trait Foo {}

struct Bar<'a> {
    w: &'a Foo + Copy,   // error, use &'a (Foo + Copy)
    x: &'a Foo + 'a,     // error, use &'a (Foo + 'a)
    y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)
    z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)
}
```

More details can be found in [RFC 438].

[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
"##,

E0536: r##"
The `not` cfg-predicate was malformed.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` predicate expects one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0537: r##"
An unknown predicate was used inside the `cfg` attribute.

Erroneous code example:

```compile_fail,E0537
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

pub fn main() {}
```

The `cfg` attribute supports only three kinds of predicates:

 * any
 * all
 * not

Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0541: r##"
An unknown meta item was used.

Erroneous code example:

```compile_fail,E0541
#[deprecated(
    since="1.0.0",
    // error: unknown meta item
    reason="Example invalid meta item. Should be 'note'")
]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. The keys provided
must be one of the valid keys for the specified attribute.

To fix the problem, either remove the unknown meta item, or rename it if you
provided the wrong name.

In the erroneous code example above, the wrong name was provided, so changing
to a correct one it will fix the error. Example:

```
#[deprecated(
    since="1.0.0",
    note="This is a valid meta item for the deprecated attribute."
)]
fn deprecated_function() {}
```
"##,

E0552: r##"
A unrecognized representation attribute was used.

Erroneous code example:

```compile_fail,E0552
#[repr(D)] // error: unrecognized representation hint
struct MyStruct {
    my_field: usize
}
```

You can use a `repr` attribute to tell the compiler how you want a struct or
enum to be laid out in memory.

Make sure you're using one of the supported options:

```
#[repr(C)] // ok!
struct MyStruct {
    my_field: usize
}
```

For more information about specifying representations, see the ["Alternative
Representations" section] of the Rustonomicon.

["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html
"##,

E0554: r##"
Feature attributes are only allowed on the nightly release channel. Stable or
beta compilers will not comply.

Example of erroneous code (on a stable compiler):

```ignore (depends on release channel)
#![feature(non_ascii_idents)] // error: #![feature] may not be used on the
                              //        stable release channel
```

If you need the feature, make sure to use a nightly release of the compiler
(but be warned that the feature may be removed or altered in the future).
"##,

E0557: r##"
A feature attribute named a feature that has been removed.

Erroneous code example:

```compile_fail,E0557
#![feature(managed_boxes)] // error: feature has been removed
```

Delete the offending feature attribute.
"##,

E0565: r##"
A literal was used in an attribute that doesn't support literals.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#![feature(attr_literals)]

#[inline("always")] // error: unsupported literal
pub fn something() {}
```

Literals in attributes are new and largely unsupported. Work to support literals
where appropriate is ongoing. Try using an unquoted name instead:

```
#[inline(always)]
pub fn something() {}
```
"##,

E0583: r##"
A file wasn't found for an out-of-line module.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
mod file_that_doesnt_exist; // error: file not found for module

fn main() {}
```

Please be sure that a file corresponding to the module exists. If you
want to use a module named `file_that_doesnt_exist`, you need to have a file
named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the
same directory.
"##,

E0585: r##"
A documentation comment that doesn't document anything was found.

Erroneous code example:

```compile_fail,E0585
fn main() {
    // The following doc comment will fail:
    /// This is a useless doc comment!
}
```

Documentation comments need to be followed by items, including functions,
types, modules, etc. Examples:

```
/// I'm documenting the following struct:
struct Foo;

/// I'm documenting the following function:
fn foo() {}
```
"##,

E0586: r##"
An inclusive range was used with no end.

Erroneous code example:

```compile_fail,E0586
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=]; // error: inclusive range was used with no end
}
```

An inclusive range needs an end in order to *include* it. If you just need a
start and no end, use a non-inclusive range (with `..`):

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..]; // ok!
}
```

Or put an end to your inclusive range:

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=3]; // ok!
}
```
"##,

E0589: r##"
The value of `N` that was specified for `repr(align(N))` was not a power
of two, or was greater than 2^29.

```compile_fail,E0589
#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
enum Foo {
    Bar(u64),
}
```
"##,

E0658: r##"
An unstable feature was used.

Erroneous code example:

```compile_fail,E658
#[repr(u128)] // error: use of unstable library feature 'repr128'
enum Foo {
    Bar(u64),
}
```

If you're using a stable or a beta version of rustc, you won't be able to use
any unstable features. In order to do so, please switch to a nightly version of
rustc (by using rustup).

If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:

```
#![feature(repr128)]

#[repr(u128)] // ok!
enum Foo {
    Bar(u64),
}
```
"##,

E0633: r##"
The `unwind` attribute was malformed.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[unwind()] // error: expected one argument
pub extern fn something() {}

fn main() {}
```

The `#[unwind]` attribute should be used as follows:

- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
  should abort the process if it attempts to unwind. This is the safer
  and preferred option.

- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
  should be allowed to unwind. This can easily result in Undefined
  Behavior (UB), so be careful.

NB. The default behavior here is "allowed", but this is unspecified
and likely to change in the future.

"##,

}

register_diagnostics! {
    E0538, // multiple [same] items
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0553, // multiple rustc_const_unstable attributes
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0584, // file for module `..` found at both .. and ..
    E0629, // missing 'feature' (rustc_const_unstable)
    E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute
    E0693, // incorrect `repr(align)` attribute format
    E0694, // an unknown tool name found in scoped attributes
}
<commit_msg>Rollup merge of #51510 - Havvy:diagnostic-list, r=GuillaumeGomez<commit_after>// Copyright 2016 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.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0178: r##"
In types, the `+` type operator has low precedence, so it is often necessary
to use parentheses.

For example:

```compile_fail,E0178
trait Foo {}

struct Bar<'a> {
    w: &'a Foo + Copy,   // error, use &'a (Foo + Copy)
    x: &'a Foo + 'a,     // error, use &'a (Foo + 'a)
    y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)
    z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)
}
```

More details can be found in [RFC 438].

[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
"##,

E0536: r##"
The `not` cfg-predicate was malformed.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` predicate expects one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0537: r##"
An unknown predicate was used inside the `cfg` attribute.

Erroneous code example:

```compile_fail,E0537
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

pub fn main() {}
```

The `cfg` attribute supports only three kinds of predicates:

 * any
 * all
 * not

Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0538: r##"
Attribute contains same meta item more than once.

Erroneous code example:

```compile_fail,E0538
#[deprecated(
    since="1.0.0",
    note="First deprecation note.",
    note="Second deprecation note." // error: multiple same meta item
)]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. Each key may only be
used once in each attribute.

To fix the problem, remove all but one of the meta items with the same key.

Example:

```
#[deprecated(
    since="1.0.0",
    note="First deprecation note."
)]
fn deprecated_function() {}
```
"##,

E0541: r##"
An unknown meta item was used.

Erroneous code example:

```compile_fail,E0541
#[deprecated(
    since="1.0.0",
    // error: unknown meta item
    reason="Example invalid meta item. Should be 'note'")
]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. The keys provided
must be one of the valid keys for the specified attribute.

To fix the problem, either remove the unknown meta item, or rename it if you
provided the wrong name.

In the erroneous code example above, the wrong name was provided, so changing
to a correct one it will fix the error. Example:

```
#[deprecated(
    since="1.0.0",
    note="This is a valid meta item for the deprecated attribute."
)]
fn deprecated_function() {}
```
"##,

E0552: r##"
A unrecognized representation attribute was used.

Erroneous code example:

```compile_fail,E0552
#[repr(D)] // error: unrecognized representation hint
struct MyStruct {
    my_field: usize
}
```

You can use a `repr` attribute to tell the compiler how you want a struct or
enum to be laid out in memory.

Make sure you're using one of the supported options:

```
#[repr(C)] // ok!
struct MyStruct {
    my_field: usize
}
```

For more information about specifying representations, see the ["Alternative
Representations" section] of the Rustonomicon.

["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html
"##,

E0554: r##"
Feature attributes are only allowed on the nightly release channel. Stable or
beta compilers will not comply.

Example of erroneous code (on a stable compiler):

```ignore (depends on release channel)
#![feature(non_ascii_idents)] // error: #![feature] may not be used on the
                              //        stable release channel
```

If you need the feature, make sure to use a nightly release of the compiler
(but be warned that the feature may be removed or altered in the future).
"##,

E0557: r##"
A feature attribute named a feature that has been removed.

Erroneous code example:

```compile_fail,E0557
#![feature(managed_boxes)] // error: feature has been removed
```

Delete the offending feature attribute.
"##,

E0565: r##"
A literal was used in an attribute that doesn't support literals.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#![feature(attr_literals)]

#[inline("always")] // error: unsupported literal
pub fn something() {}
```

Literals in attributes are new and largely unsupported. Work to support literals
where appropriate is ongoing. Try using an unquoted name instead:

```
#[inline(always)]
pub fn something() {}
```
"##,

E0583: r##"
A file wasn't found for an out-of-line module.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
mod file_that_doesnt_exist; // error: file not found for module

fn main() {}
```

Please be sure that a file corresponding to the module exists. If you
want to use a module named `file_that_doesnt_exist`, you need to have a file
named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the
same directory.
"##,

E0585: r##"
A documentation comment that doesn't document anything was found.

Erroneous code example:

```compile_fail,E0585
fn main() {
    // The following doc comment will fail:
    /// This is a useless doc comment!
}
```

Documentation comments need to be followed by items, including functions,
types, modules, etc. Examples:

```
/// I'm documenting the following struct:
struct Foo;

/// I'm documenting the following function:
fn foo() {}
```
"##,

E0586: r##"
An inclusive range was used with no end.

Erroneous code example:

```compile_fail,E0586
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=]; // error: inclusive range was used with no end
}
```

An inclusive range needs an end in order to *include* it. If you just need a
start and no end, use a non-inclusive range (with `..`):

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..]; // ok!
}
```

Or put an end to your inclusive range:

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=3]; // ok!
}
```
"##,

E0589: r##"
The value of `N` that was specified for `repr(align(N))` was not a power
of two, or was greater than 2^29.

```compile_fail,E0589
#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
enum Foo {
    Bar(u64),
}
```
"##,

E0658: r##"
An unstable feature was used.

Erroneous code example:

```compile_fail,E658
#[repr(u128)] // error: use of unstable library feature 'repr128'
enum Foo {
    Bar(u64),
}
```

If you're using a stable or a beta version of rustc, you won't be able to use
any unstable features. In order to do so, please switch to a nightly version of
rustc (by using rustup).

If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:

```
#![feature(repr128)]

#[repr(u128)] // ok!
enum Foo {
    Bar(u64),
}
```
"##,

E0633: r##"
The `unwind` attribute was malformed.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[unwind()] // error: expected one argument
pub extern fn something() {}

fn main() {}
```

The `#[unwind]` attribute should be used as follows:

- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
  should abort the process if it attempts to unwind. This is the safer
  and preferred option.

- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
  should be allowed to unwind. This can easily result in Undefined
  Behavior (UB), so be careful.

NB. The default behavior here is "allowed", but this is unspecified
and likely to change in the future.

"##,

}

register_diagnostics! {
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0553, // multiple rustc_const_unstable attributes
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0584, // file for module `..` found at both .. and ..
    E0629, // missing 'feature' (rustc_const_unstable)
    E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute
    E0693, // incorrect `repr(align)` attribute format
    E0694, // an unknown tool name found in scoped attributes
}
<|endoftext|>


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

//! A task that takes a URL and streams back the binary data.

use file_loader;
use http_loader;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::url::Url;
use util::spawn_listener;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(Url, Chan<ProgressMsg>),
    Exit
}

/// Messages sent in response to a `Load` message
#[deriving(Eq)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(~[u8]),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), ()>)
}

/// Handle to a resource task
pub type ResourceTask = SharedChan<ControlMsg>;

/**
Creates a task to load a specific resource

The ResourceManager delegates loading to a different type of loader task for
each URL scheme
*/
type LoaderTaskFactory = ~fn() -> ~fn(url: Url, Chan<ProgressMsg>);

pub type LoaderTask = ~fn(url: Url, Chan<ProgressMsg>);

/// Create a ResourceTask with the default loaders
pub fn ResourceTask() -> ResourceTask {
    let file_loader_factory: LoaderTaskFactory = file_loader::factory;
    let http_loader_factory: LoaderTaskFactory = http_loader::factory;
    let loaders = ~[
        (~"file", file_loader_factory),
        (~"http", http_loader_factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    let loaders_cell = Cell::new(loaders);
    let chan = do spawn_listener |from_client| {
        // TODO: change copy to move once we can move out of closures
        ResourceManager(from_client, loaders_cell.take()).start()
    };
    SharedChan::new(chan)
}

pub struct ResourceManager {
    from_client: Port<ControlMsg>,
    /// Per-scheme resource loaders
    loaders: ~[(~str, LoaderTaskFactory)],
}

pub fn ResourceManager(from_client: Port<ControlMsg>,
                       loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceManager {
    ResourceManager {
        from_client : from_client,
        loaders : loaders,
    }
}

impl ResourceManager {
    fn start(&self) {
        loop {
            match self.from_client.recv() {
              Load(url, progress_chan) => {
                self.load(url.clone(), progress_chan)
              }
              Exit => {
                break
              }
            }
        }
    }

    fn load(&self, url: Url, progress_chan: Chan<ProgressMsg>) {

        match self.get_loader_factory(&url) {
            Some(loader_factory) => {
                debug!("resource_task: loading url: %s", url.to_str());
                loader_factory(url, progress_chan);
            }
            None => {
                debug!("resource_task: no loader for scheme %s", url.scheme);
                progress_chan.send(Done(Err(())));
            }
        }
    }

    fn get_loader_factory(&self, url: &Url) -> Option<LoaderTask> {
        for scheme_loader in self.loaders.iter() {
            match *scheme_loader {
                (ref scheme, ref loader_factory) => {
	            if (*scheme) == url.scheme {
                        return Some((*loader_factory)());
                    }
	        }
            }
        }
        return None;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = Port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    match progress.recv() {
      Done(result) => { assert!(result.is_err()) }
      _ => fail
    }
    resource_task.send(Exit);
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = |_url: Url, progress_chan: Chan<ProgressMsg>| {
        progress_chan.send(Payload(payload.clone()));
        progress_chan.send(Done(Ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = Port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert!(progress.recv() == Payload(payload));
    assert!(progress.recv() == Done(Ok(())));
    resource_task.send(Exit);
}
<commit_msg>Remove old lint mode annotation.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A task that takes a URL and streams back the binary data.

use file_loader;
use http_loader;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::url::Url;
use util::spawn_listener;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(Url, Chan<ProgressMsg>),
    Exit
}

/// Messages sent in response to a `Load` message
#[deriving(Eq)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(~[u8]),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), ()>)
}

/// Handle to a resource task
pub type ResourceTask = SharedChan<ControlMsg>;

/**
Creates a task to load a specific resource

The ResourceManager delegates loading to a different type of loader task for
each URL scheme
*/
type LoaderTaskFactory = ~fn() -> ~fn(url: Url, Chan<ProgressMsg>);

pub type LoaderTask = ~fn(url: Url, Chan<ProgressMsg>);

/// Create a ResourceTask with the default loaders
pub fn ResourceTask() -> ResourceTask {
    let file_loader_factory: LoaderTaskFactory = file_loader::factory;
    let http_loader_factory: LoaderTaskFactory = http_loader::factory;
    let loaders = ~[
        (~"file", file_loader_factory),
        (~"http", http_loader_factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    let loaders_cell = Cell::new(loaders);
    let chan = do spawn_listener |from_client| {
        // TODO: change copy to move once we can move out of closures
        ResourceManager(from_client, loaders_cell.take()).start()
    };
    SharedChan::new(chan)
}

pub struct ResourceManager {
    from_client: Port<ControlMsg>,
    /// Per-scheme resource loaders
    loaders: ~[(~str, LoaderTaskFactory)],
}

pub fn ResourceManager(from_client: Port<ControlMsg>,
                       loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceManager {
    ResourceManager {
        from_client : from_client,
        loaders : loaders,
    }
}

impl ResourceManager {
    fn start(&self) {
        loop {
            match self.from_client.recv() {
              Load(url, progress_chan) => {
                self.load(url.clone(), progress_chan)
              }
              Exit => {
                break
              }
            }
        }
    }

    fn load(&self, url: Url, progress_chan: Chan<ProgressMsg>) {

        match self.get_loader_factory(&url) {
            Some(loader_factory) => {
                debug!("resource_task: loading url: %s", url.to_str());
                loader_factory(url, progress_chan);
            }
            None => {
                debug!("resource_task: no loader for scheme %s", url.scheme);
                progress_chan.send(Done(Err(())));
            }
        }
    }

    fn get_loader_factory(&self, url: &Url) -> Option<LoaderTask> {
        for scheme_loader in self.loaders.iter() {
            match *scheme_loader {
                (ref scheme, ref loader_factory) => {
	            if (*scheme) == url.scheme {
                        return Some((*loader_factory)());
                    }
	        }
            }
        }
        return None;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = Port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    match progress.recv() {
      Done(result) => { assert!(result.is_err()) }
      _ => fail
    }
    resource_task.send(Exit);
}

#[test]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = |_url: Url, progress_chan: Chan<ProgressMsg>| {
        progress_chan.send(Payload(payload.clone()));
        progress_chan.send(Done(Ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = Port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert!(progress.recv() == Payload(payload));
    assert!(progress.recv() == Done(Ok(())));
    resource_task.send(Exit);
}
<|endoftext|>


<commit_before>use std::convert::TryInto;

use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
    Data, DeriveInput, Field, Ident, Lit, Meta, MetaList, MetaNameValue, NestedMeta, Visibility,
};

/// Representing the struct we are deriving
pub struct Input {
    /// The input struct name
    pub name: Ident,
    /// The list of traits to derive passed to `soa_derive` attribute
    pub derives: Vec<Ident>,
    /// The list of fields in the struct
    pub fields: Vec<Field>,
    /// The struct overall visibility
    pub visibility: Visibility,

    pub vec_attrs: Vec<Meta>,
    pub slice_attrs: Vec<Meta>,
    pub ref_attrs: Vec<Meta>,
    pub ptr_attrs: Vec<Meta>,
}

impl Input {
    pub fn new(input: DeriveInput) -> Input {
        let fields = match input.data {
            Data::Struct(s) => s.fields.iter().cloned().collect::<Vec<_>>(),
            _ => panic!("#[derive(StructOfArray)] only supports structs."),
        };

        let mut derives: Vec<Ident> = vec![];
        let mut vec_attrs = Vec::new();
        let mut slice_attrs = Vec::new();
        let mut ref_attrs = Vec::new();
        let mut ptr_attrs = Vec::new();
        for attr in input.attrs {
            if let Ok(meta) = attr.parse_meta() {
                if meta.path().is_ident("soa_derive") {
                    match meta {
                        Meta::NameValue(MetaNameValue {
                            lit: Lit::Str(string),
                            ..
                        }) => {
                            for value in string.value().split(',') {
                                derives.push(Ident::new(value.trim(), Span::call_site()));
                            }
                        }
                        _ => panic!(
                            "expected #[soa_derive = \"Traits, To, Derive\"], got #[{}]",
                            quote!(#meta)
                        ),
                    }
                } else if meta.path().is_ident("soa_attr") {
                    match meta.clone() {
                        Meta::List(MetaList { nested, .. }) => {
                            let [soa_type, attr]: [NestedMeta; 2] =
                                nested.into_iter().collect::<Vec<_>>().try_into().unwrap_or_else(|_| panic!("expected #[soa_derive(\"Types, To, Add, Attribute\", \"Attributes\", got #[{}])]", quote!(#meta)));
                            let attr = match attr {
                                NestedMeta::Meta(meta) => meta,
                                NestedMeta::Lit(_) => {
                                    panic!("expected a attribute, got {}", quote!(attr))
                                }
                            };
                            match soa_type {
                                NestedMeta::Meta(Meta::Path(path)) => match path.get_ident() {
                                    Some(ident) => match ident.to_string().as_str() {
                                        "Vec" => vec_attrs.push(attr),
                                        "Slice" => slice_attrs.push(attr),
                                        "Ref" => ref_attrs.push(attr),
                                        "ptr" => ptr_attrs.push(attr),
                                        _ => panic!("expected a soa type, got {}", ident),
                                    },
                                    None => {
                                        panic!("expected a soa type, got {}", quote!(#path))
                                    }
                                },
                                _ => {
                                    panic!("expected a soa type, got {}", quote!(#soa_type))
                                }
                            }
                        }
                        _ => panic!("expected #[soa_attr(...), got #[{}]]", quote!(#meta)),
                    }
                }
            }
        }

        Input {
            name: input.ident,
            derives: derives,
            fields: fields,
            visibility: input.vis,
            vec_attrs,
            slice_attrs,
            ref_attrs,
            ptr_attrs,
        }
    }

    pub fn derive(&self) -> TokenStream {
        if self.derives.is_empty() {
            TokenStream::new()
        } else {
            let derives = &self.derives;
            quote!(
                #[derive(
                    #(#derives,)*
                )]
            )
        }
    }

    pub fn derive_with_exceptions(&self) -> TokenStream {
        if self.derives.is_empty() {
            TokenStream::new()
        } else {
            let derives = &self
                .derives
                .iter()
                .cloned()
                .filter(|name| name != "Clone")
                .filter(|name| name != "Deserialize")
                .filter(|name| name != "Serialize")
                .collect::<Vec<_>>();
            quote!(
                #[derive(
                    #(#derives,)*
                )]
            )
        }
    }

    pub fn vec_name(&self) -> Ident {
        Ident::new(&format!("{}Vec", self.name), Span::call_site())
    }

    pub fn slice_name(&self) -> Ident {
        Ident::new(&format!("{}Slice", self.name), Span::call_site())
    }

    pub fn slice_mut_name(&self) -> Ident {
        Ident::new(&format!("{}SliceMut", self.name), Span::call_site())
    }

    pub fn ref_name(&self) -> Ident {
        Ident::new(&format!("{}Ref", self.name), Span::call_site())
    }

    pub fn ref_mut_name(&self) -> Ident {
        Ident::new(&format!("{}RefMut", self.name), Span::call_site())
    }

    pub fn ptr_name(&self) -> Ident {
        Ident::new(&format!("{}Ptr", self.name), Span::call_site())
    }

    pub fn ptr_mut_name(&self) -> Ident {
        Ident::new(&format!("{}PtrMut", self.name), Span::call_site())
    }
}
<commit_msg>fix: typo<commit_after>use std::convert::TryInto;

use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
    Data, DeriveInput, Field, Ident, Lit, Meta, MetaList, MetaNameValue, NestedMeta, Visibility,
};

/// Representing the struct we are deriving
pub struct Input {
    /// The input struct name
    pub name: Ident,
    /// The list of traits to derive passed to `soa_derive` attribute
    pub derives: Vec<Ident>,
    /// The list of fields in the struct
    pub fields: Vec<Field>,
    /// The struct overall visibility
    pub visibility: Visibility,

    pub vec_attrs: Vec<Meta>,
    pub slice_attrs: Vec<Meta>,
    pub ref_attrs: Vec<Meta>,
    pub ptr_attrs: Vec<Meta>,
}

impl Input {
    pub fn new(input: DeriveInput) -> Input {
        let fields = match input.data {
            Data::Struct(s) => s.fields.iter().cloned().collect::<Vec<_>>(),
            _ => panic!("#[derive(StructOfArray)] only supports structs."),
        };

        let mut derives: Vec<Ident> = vec![];
        let mut vec_attrs = Vec::new();
        let mut slice_attrs = Vec::new();
        let mut ref_attrs = Vec::new();
        let mut ptr_attrs = Vec::new();
        for attr in input.attrs {
            if let Ok(meta) = attr.parse_meta() {
                if meta.path().is_ident("soa_derive") {
                    match meta {
                        Meta::NameValue(MetaNameValue {
                            lit: Lit::Str(string),
                            ..
                        }) => {
                            for value in string.value().split(',') {
                                derives.push(Ident::new(value.trim(), Span::call_site()));
                            }
                        }
                        _ => panic!(
                            "expected #[soa_derive = \"Traits, To, Derive\"], got #[{}]",
                            quote!(#meta)
                        ),
                    }
                } else if meta.path().is_ident("soa_attr") {
                    match meta.clone() {
                        Meta::List(MetaList { nested, .. }) => {
                            let [soa_type, attr]: [NestedMeta; 2] =
                                nested.into_iter().collect::<Vec<_>>().try_into().unwrap_or_else(|_| panic!("expected #[soa_derive(\"Types, To, Add, Attribute\", \"Attributes\", got #[{}])]", quote!(#meta)));
                            let attr = match attr {
                                NestedMeta::Meta(meta) => meta,
                                NestedMeta::Lit(_) => {
                                    panic!("expected a attribute, got {}", quote!(attr))
                                }
                            };
                            match soa_type {
                                NestedMeta::Meta(Meta::Path(path)) => match path.get_ident() {
                                    Some(ident) => match ident.to_string().as_str() {
                                        "Vec" => vec_attrs.push(attr),
                                        "Slice" => slice_attrs.push(attr),
                                        "Ref" => ref_attrs.push(attr),
                                        "Ptr" => ptr_attrs.push(attr),
                                        _ => panic!("expected a soa type, got {}", ident),
                                    },
                                    None => {
                                        panic!("expected a soa type, got {}", quote!(#path))
                                    }
                                },
                                _ => {
                                    panic!("expected a soa type, got {}", quote!(#soa_type))
                                }
                            }
                        }
                        _ => panic!("expected #[soa_attr(...), got #[{}]]", quote!(#meta)),
                    }
                }
            }
        }

        Input {
            name: input.ident,
            derives: derives,
            fields: fields,
            visibility: input.vis,
            vec_attrs,
            slice_attrs,
            ref_attrs,
            ptr_attrs,
        }
    }

    pub fn derive(&self) -> TokenStream {
        if self.derives.is_empty() {
            TokenStream::new()
        } else {
            let derives = &self.derives;
            quote!(
                #[derive(
                    #(#derives,)*
                )]
            )
        }
    }

    pub fn derive_with_exceptions(&self) -> TokenStream {
        if self.derives.is_empty() {
            TokenStream::new()
        } else {
            let derives = &self.derives.iter()
                                       .cloned()
                                       .filter(|name| name != "Clone")
                                       .filter(|name| name != "Deserialize")
                                       .filter(|name| name != "Serialize")
                                       .collect::<Vec<_>>();
            quote!(
                #[derive(
                    #(#derives,)*
                )]
            )
        }
    }

    pub fn vec_name(&self) -> Ident {
        Ident::new(&format!("{}Vec", self.name), Span::call_site())
    }

    pub fn slice_name(&self) -> Ident {
        Ident::new(&format!("{}Slice", self.name), Span::call_site())
    }

    pub fn slice_mut_name(&self) -> Ident {
        Ident::new(&format!("{}SliceMut", self.name), Span::call_site())
    }

    pub fn ref_name(&self) -> Ident {
        Ident::new(&format!("{}Ref", self.name), Span::call_site())
    }

    pub fn ref_mut_name(&self) -> Ident {
        Ident::new(&format!("{}RefMut", self.name), Span::call_site())
    }

    pub fn ptr_name(&self) -> Ident {
        Ident::new(&format!("{}Ptr", self.name), Span::call_site())
    }

    pub fn ptr_mut_name(&self) -> Ident {
        Ident::new(&format!("{}PtrMut", self.name), Span::call_site())
    }
}
<|endoftext|>


<commit_before>use alloc::sync::Arc;
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::{cmp, str};
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Mutex, RwLock};

use crate::context;
use crate::syscall::data::Stat;
use crate::syscall::error::*;
use crate::syscall::flag::{O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END};
use crate::syscall::scheme::Scheme;
use crate::scheme::{self, SchemeNamespace, SchemeId};
use crate::scheme::user::{UserInner, UserScheme};

struct FolderInner {
    data: Box<[u8]>,
    pos: Mutex<usize>
}

impl FolderInner {
    fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let mut pos = self.pos.lock();

        while i < buf.len() && *pos < self.data.len() {
            buf[i] = self.data[*pos];
            i += 1;
            *pos += 1;
        }

        Ok(i)
    }

    fn seek(&self, pos: usize, whence: usize) -> Result<usize> {
        let mut seek = self.pos.lock();
        *seek = match whence {
            SEEK_SET => cmp::min(self.data.len(), pos),
            SEEK_CUR => cmp::max(0, cmp::min(self.data.len() as isize, *seek as isize + pos as isize)) as usize,
            SEEK_END => cmp::max(0, cmp::min(self.data.len() as isize, self.data.len() as isize + pos as isize)) as usize,
            _ => return Err(Error::new(EINVAL))
        };

        Ok(*seek)
    }
}

#[derive(Clone)]
enum Handle {
    Scheme(Arc<UserInner>),
    File(Arc<Box<[u8]>>),
    Folder(Arc<FolderInner>)
}

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Handle>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        let path_utf8 = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
        let path_trimmed = path_utf8.trim_matches('/');

        //TODO: Make this follow standards for flags and errors
        if flags & O_CREAT == O_CREAT {
            if uid == 0 {
                let context = {
                    let contexts = context::contexts();
                    let context = contexts.current().ok_or(Error::new(ESRCH))?;
                    Arc::downgrade(&context)
                };

                let id = self.next_id.fetch_add(1, Ordering::SeqCst);

                let inner = {
                    let path_box = path_trimmed.as_bytes().to_vec().into_boxed_slice();
                    let mut schemes = scheme::schemes_mut();
                    let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                    schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                        inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                        Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                    })?;
                    inner
                };

                self.handles.write().insert(id, Handle::Scheme(inner));

                Ok(id)
            } else {
                Err(Error::new(EACCES))
            }
        } else if path_trimmed.is_empty() {
            let scheme_ns = {
                let contexts = context::contexts();
                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                let context = context_lock.read();
                context.ens
            };

            let mut data = Vec::new();
            {
                let schemes = scheme::schemes();
                for (name, _scheme_id) in schemes.iter_name(scheme_ns) {
                    data.extend_from_slice(name);
                    data.push(b'\n');
                }
            }

            let inner = Arc::new(FolderInner {
                data: data.into_boxed_slice(),
                pos: Mutex::new(0)
            });

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);
            self.handles.write().insert(id, Handle::Folder(inner));
            Ok(id)
        } else {
            let inner = Arc::new(
                path_trimmed.as_bytes().to_vec().into_boxed_slice()
            );

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);
            self.handles.write().insert(id, Handle::File(inner));
            Ok(id)
        }
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.read(buf)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(inner) => {
                inner.read(buf)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.write(buf)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn seek(&self, file: usize, pos: usize, whence: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(_) => {
                Err(Error::new(EBADF))
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(inner) => {
                inner.seek(pos, whence)
            }
        }
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.fevent(flags)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        match handle {
            Handle::Scheme(inner) => {
                let mut j = 0;
                while i < buf.len() && j < inner.name.len() {
                    buf[i] = inner.name[j];
                    i += 1;
                    j += 1;
                }
            },
            Handle::File(inner) => {
                let mut j = 0;
                while i < buf.len() && j < inner.len() {
                    buf[i] = inner[j];
                    i += 1;
                    j += 1;
                }
            },
            Handle::Folder(_) => ()
        }

        Ok(i)
    }

    fn fstat(&self, file: usize, stat: &mut Stat) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(_) => {
                stat.st_mode = MODE_FILE;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = 0;
            },
            Handle::File(_) => {
                stat.st_mode = MODE_FILE;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = 0;
            },
            Handle::Folder(inner) => {
                stat.st_mode = MODE_DIR;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = inner.data.len() as u64;
            }
        }

        Ok(0)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.fsync()
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn close(&self, file: usize) -> Result<usize> {
        self.handles.write().remove(&file);
        Ok(0)
    }
}
<commit_msg>Remove scheme if closed<commit_after>use alloc::sync::Arc;
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::{cmp, str};
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Mutex, RwLock};

use crate::context;
use crate::syscall::data::Stat;
use crate::syscall::error::*;
use crate::syscall::flag::{O_CREAT, MODE_FILE, MODE_DIR, SEEK_SET, SEEK_CUR, SEEK_END};
use crate::syscall::scheme::Scheme;
use crate::scheme::{self, SchemeNamespace, SchemeId};
use crate::scheme::user::{UserInner, UserScheme};

struct FolderInner {
    data: Box<[u8]>,
    pos: Mutex<usize>
}

impl FolderInner {
    fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let mut pos = self.pos.lock();

        while i < buf.len() && *pos < self.data.len() {
            buf[i] = self.data[*pos];
            i += 1;
            *pos += 1;
        }

        Ok(i)
    }

    fn seek(&self, pos: usize, whence: usize) -> Result<usize> {
        let mut seek = self.pos.lock();
        *seek = match whence {
            SEEK_SET => cmp::min(self.data.len(), pos),
            SEEK_CUR => cmp::max(0, cmp::min(self.data.len() as isize, *seek as isize + pos as isize)) as usize,
            SEEK_END => cmp::max(0, cmp::min(self.data.len() as isize, self.data.len() as isize + pos as isize)) as usize,
            _ => return Err(Error::new(EINVAL))
        };

        Ok(*seek)
    }
}

#[derive(Clone)]
enum Handle {
    Scheme(Arc<UserInner>),
    File(Arc<Box<[u8]>>),
    Folder(Arc<FolderInner>)
}

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Handle>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        let path_utf8 = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
        let path_trimmed = path_utf8.trim_matches('/');

        //TODO: Make this follow standards for flags and errors
        if flags & O_CREAT == O_CREAT {
            if uid == 0 {
                let context = {
                    let contexts = context::contexts();
                    let context = contexts.current().ok_or(Error::new(ESRCH))?;
                    Arc::downgrade(&context)
                };

                let id = self.next_id.fetch_add(1, Ordering::SeqCst);

                let inner = {
                    let path_box = path_trimmed.as_bytes().to_vec().into_boxed_slice();
                    let mut schemes = scheme::schemes_mut();
                    let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                    schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                        inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                        Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                    })?;
                    inner
                };

                self.handles.write().insert(id, Handle::Scheme(inner));

                Ok(id)
            } else {
                Err(Error::new(EACCES))
            }
        } else if path_trimmed.is_empty() {
            let scheme_ns = {
                let contexts = context::contexts();
                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                let context = context_lock.read();
                context.ens
            };

            let mut data = Vec::new();
            {
                let schemes = scheme::schemes();
                for (name, _scheme_id) in schemes.iter_name(scheme_ns) {
                    data.extend_from_slice(name);
                    data.push(b'\n');
                }
            }

            let inner = Arc::new(FolderInner {
                data: data.into_boxed_slice(),
                pos: Mutex::new(0)
            });

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);
            self.handles.write().insert(id, Handle::Folder(inner));
            Ok(id)
        } else {
            let inner = Arc::new(
                path_trimmed.as_bytes().to_vec().into_boxed_slice()
            );

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);
            self.handles.write().insert(id, Handle::File(inner));
            Ok(id)
        }
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.read(buf)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(inner) => {
                inner.read(buf)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.write(buf)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn seek(&self, file: usize, pos: usize, whence: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(_) => {
                Err(Error::new(EBADF))
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(inner) => {
                inner.seek(pos, whence)
            }
        }
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.fevent(flags)
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        match handle {
            Handle::Scheme(inner) => {
                let mut j = 0;
                while i < buf.len() && j < inner.name.len() {
                    buf[i] = inner.name[j];
                    i += 1;
                    j += 1;
                }
            },
            Handle::File(inner) => {
                let mut j = 0;
                while i < buf.len() && j < inner.len() {
                    buf[i] = inner[j];
                    i += 1;
                    j += 1;
                }
            },
            Handle::Folder(_) => ()
        }

        Ok(i)
    }

    fn fstat(&self, file: usize, stat: &mut Stat) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(_) => {
                stat.st_mode = MODE_FILE;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = 0;
            },
            Handle::File(_) => {
                stat.st_mode = MODE_FILE;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = 0;
            },
            Handle::Folder(inner) => {
                stat.st_mode = MODE_DIR;
                stat.st_uid = 0;
                stat.st_gid = 0;
                stat.st_size = inner.data.len() as u64;
            }
        }

        Ok(0)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let handle = {
            let handles = self.handles.read();
            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
            handle.clone()
        };

        match handle {
            Handle::Scheme(inner) => {
                inner.fsync()
            },
            Handle::File(_) => {
                Err(Error::new(EBADF))
            },
            Handle::Folder(_) => {
                Err(Error::new(EBADF))
            }
        }
    }

    fn close(&self, file: usize) -> Result<usize> {
        let handle = self.handles.write().remove(&file).ok_or(Error::new(EBADF))?;
        match handle {
            Handle::Scheme(inner) => {
                let scheme_id = inner.scheme_id.load(Ordering::SeqCst);
                let mut schemes = scheme::schemes_mut();
                schemes.remove(scheme_id);
            },
            _ => ()
        }
        Ok(0)
    }
}
<|endoftext|>