<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
#![allow(
    clippy::unused_unit,
    clippy::needless_return,
    clippy::never_loop,
    clippy::option_map_unit_fn
)]

use crate::Error;
use osmpbfreader::{OsmId, OsmObj, StoreObjs};
use slog_scope::info;

#[cfg(feature = "db-storage")]
use crate::settings::osm2mimir::Database;

#[cfg(feature = "db-storage")]
use slog_scope::error;

#[cfg(feature = "db-storage")]
use std::fs;

#[cfg(feature = "db-storage")]
use std::path::PathBuf;

#[cfg(feature = "db-storage")]
use std::collections::HashMap;

use std::borrow::Cow;
use std::collections::BTreeMap;

use super::street::Kind;

#[cfg(feature = "db-storage")]
use rusqlite::{Connection, DropBehavior, ToSql, NO_PARAMS};

#[cfg(feature = "db-storage")]
macro_rules! err_logger {
    ($obj:expr, $err_msg:expr) => {
        match $obj {
            Ok(x) => Some(x),
            Err(e) => {
                error!("{}: {}", $err_msg, e);
                None
            }
        }?
    };
    ($obj:expr, $err_msg:expr, $ret:expr) => {
        match $obj {
            Ok(x) => x,
            Err(e) => {
                error!("{}: {}", $err_msg, e);
                return $ret;
            }
        }
    };
}

macro_rules! get_kind {
    ($obj:expr) => {
        if $obj.is_node() {
            &0
        } else if $obj.is_way() {
            &1
        } else if $obj.is_relation() {
            &2
        } else {
            panic!("Unknown OSM object kind!")
        }
    };
}

pub trait Getter {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>>;
}

impl Getter for BTreeMap<OsmId, OsmObj> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        self.get(key).map(|x| Cow::Borrowed(x))
    }
}

#[cfg(feature = "db-storage")]
pub struct DB<'a> {
    conn: Connection,
    db_file: &'a PathBuf,
    buffer: HashMap<OsmId, OsmObj>,
    db_buffer_size: usize,
}

#[cfg(feature = "db-storage")]
impl<'a> DB<'a> {
    fn new(db_file: &'a PathBuf, db_buffer_size: usize) -> Result<DB<'a>, String> {
        let _ = fs::remove_file(db_file); // we ignore any potential error
        let conn = Connection::open(&db_file)
            .map_err(|e| format!("failed to open SQLITE connection: {}", e))?;

        conn.execute(
            "CREATE TABLE ids (
                id   INTEGER NOT NULL,
                obj  BLOB NOT NULL,
                kind INTEGER NOT NULL,
                UNIQUE(id, kind)
             )",
            NO_PARAMS,
        )
        .map_err(|e| format!("failed to create table: {}", e))?;
        Ok(DB {
            conn,
            db_file,
            buffer: HashMap::with_capacity(db_buffer_size),
            db_buffer_size,
        })
    }

    fn get_from_id(&self, id: &OsmId) -> Option<Cow<OsmObj>> {
        if let Some(obj) = self.buffer.get(id) {
            return Some(Cow::Borrowed(obj));
        }
        let mut stmt = err_logger!(
            self.conn
                .prepare("SELECT obj FROM ids WHERE id=?1 AND kind=?2"),
            "DB::get_from_id: prepare failed"
        );
        let mut iter = err_logger!(
            stmt.query(&[&id.inner_id() as &dyn ToSql, get_kind!(id)]),
            "DB::get_from_id: query_map failed"
        );
        while let Some(row) = err_logger!(iter.next(), "DB::get_from_id: next failed") {
            let obj: Vec<u8> = err_logger!(row.get(0), "DB::get_from_id: failed to get obj field");
            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "DB::for_each: serde conversion failed",
                None
            );
            return Some(Cow::Owned(obj));
        }
        None
    }

    #[allow(dead_code)]
    fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        for value in self.buffer.values() {
            f(Cow::Borrowed(value));
        }
        let mut stmt = err_logger!(
            self.conn.prepare("SELECT obj FROM ids"),
            "DB::for_each: prepare failed",
            ()
        );
        let mut rows = err_logger!(stmt.query(NO_PARAMS), "DB::for_each: query_map failed", ());
        while let Some(row) = err_logger!(rows.next(), "DB::for_each: next failed", ()) {
            let obj: Vec<u8> = err_logger!(row.get(0), "DB::for_each: failed to get obj field", ());

            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "DB::for_each: serde conversion failed",
                ()
            );
            f(Cow::Owned(obj));
        }
    }

    fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        self.buffer
            .values()
            .filter(|e| *get_kind!(e) == filter as i32)
            .for_each(|value| f(Cow::Borrowed(value)));
        let mut stmt = err_logger!(
            self.conn.prepare("SELECT obj FROM ids WHERE kind=?1"),
            "DB::for_each: prepare failed",
            ()
        );
        let mut rows = err_logger!(
            stmt.query(&[&(filter as i32) as &dyn ToSql]),
            "DB::for_each: query_map failed",
            ()
        );
        while let Some(row) = err_logger!(rows.next(), "DB::for_each: next failed", ()) {
            let obj: Vec<u8> = err_logger!(row.get(0), "DB::for_each: failed to get obj field", ());

            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "DB::for_each: serde conversion failed",
                ()
            );
            f(Cow::Owned(obj));
        }
    }

    fn flush_buffer(&mut self) {
        if self.buffer.is_empty() {
            return;
        }
        let mut tx = err_logger!(
            self.conn.transaction(),
            "DB::flush_buffer: transaction creation failed",
            ()
        );
        tx.set_drop_behavior(DropBehavior::Ignore);

        {
            let mut stmt = err_logger!(
                tx.prepare("INSERT OR IGNORE INTO ids(id, obj, kind) VALUES (?1, ?2, ?3)"),
                "DB::flush_buffer: prepare failed",
                ()
            );
            for (id, obj) in self.buffer.drain() {
                let ser_obj = match bincode::serialize(&obj) {
                    Ok(s) => s,
                    Err(e) => {
                        error!("DB::flush_buffer: failed to convert to json: {}", e);
                        continue;
                    }
                };
                let kind = get_kind!(obj);
                if let Err(e) = stmt.execute(&[&id.inner_id() as &dyn ToSql, &ser_obj, kind]) {
                    error!("DB::flush_buffer: insert failed: {}", e);
                }
            }
        }
        err_logger!(
            tx.commit(),
            "DB::flush_buffer: transaction commit failed",
            ()
        );
    }
}

#[cfg(feature = "db-storage")]
impl<'a> StoreObjs for DB<'a> {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        if self.buffer.len() >= self.db_buffer_size {
            self.flush_buffer();
        }
        self.buffer.insert(id, obj);
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        if self.buffer.contains_key(id) {
            return true;
        }
        let mut stmt = err_logger!(
            self.conn
                .prepare("SELECT id FROM ids WHERE id=?1 AND kind=?2"),
            "DB::contains_key: prepare failed",
            false
        );
        let mut iter = err_logger!(
            stmt.query(&[&id.inner_id() as &dyn ToSql, get_kind!(id)]),
            "DB::contains_key: query_map failed",
            false
        );
        err_logger!(iter.next(), "DB::contains_key: no row", false).is_some()
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Getter for DB<'a> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        self.get_from_id(key)
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Drop for DB<'a> {
    fn drop(&mut self) {
        let _ = fs::remove_file(self.db_file); // we ignore any potential error
    }
}

#[cfg(feature = "db-storage")]
pub enum ObjWrapper<'a> {
    Map(BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>),
    Db(DB<'a>),
}

#[cfg(not(feature = "db-storage"))]
pub enum ObjWrapper {
    Map(BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>),
}

#[cfg(feature = "db-storage")]
impl<'a> ObjWrapper<'a> {
    pub fn new(db: &'a Option<Database>) -> Result<ObjWrapper<'a>, Error> {
        Ok(if let Some(ref db) = db {
            info!("Running with DB storage");
            ObjWrapper::Db(DB::new(&db.file, db.buffer_size).map_err(failure::err_msg)?)
        } else {
            info!("Running with BTreeMap (RAM) storage");
            ObjWrapper::Map(BTreeMap::new())
        })
    }

    #[allow(dead_code)]
    pub fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                for value in m.values() {
                    f(Cow::Borrowed(value));
                }
            }
            ObjWrapper::Db(ref db) => db.for_each(f),
        }
    }

    pub fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                m.values()
                    .filter(|e| *get_kind!(e) == filter as i32)
                    .for_each(|value| f(Cow::Borrowed(value)));
            }
            ObjWrapper::Db(ref db) => db.for_each_filter(filter, f),
        }
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Getter for ObjWrapper<'a> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        match *self {
            ObjWrapper::Map(ref m) => m.get(key).map(|x| Cow::Borrowed(x)),
            ObjWrapper::Db(ref db) => db.get(key),
        }
    }
}

#[cfg(feature = "db-storage")]
impl<'a> StoreObjs for ObjWrapper<'a> {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        match *self {
            ObjWrapper::Map(ref mut m) => {
                m.insert(id, obj);
            }
            ObjWrapper::Db(ref mut db) => db.insert(id, obj),
        }
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        match *self {
            ObjWrapper::Map(ref m) => m.contains_key(id),
            ObjWrapper::Db(ref db) => db.contains_key(id),
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl ObjWrapper {
    pub fn new() -> Result<ObjWrapper, Error> {
        info!("Running with BTreeMap (RAM) storage");
        Ok(ObjWrapper::Map(BTreeMap::new()))
    }

    #[allow(dead_code)]
    pub fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                for value in m.values() {
                    f(Cow::Borrowed(value));
                }
            }
        }
    }

    pub fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                m.values()
                    .filter(|e| *get_kind!(e) == filter as i32)
                    .for_each(|value| f(Cow::Borrowed(value)));
            }
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl Getter for ObjWrapper {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        match *self {
            ObjWrapper::Map(ref m) => m.get(key).map(|x| Cow::Borrowed(x)),
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl StoreObjs for ObjWrapper {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        match *self {
            ObjWrapper::Map(ref mut m) => {
                m.insert(id, obj);
            }
        }
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        match *self {
            ObjWrapper::Map(ref m) => m.contains_key(id),
        }
    }
}
<commit_msg>Fixed linting<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
#![allow(
    clippy::unused_unit,
    clippy::needless_return,
    clippy::never_loop,
    clippy::option_map_unit_fn
)]

use crate::Error;
use osmpbfreader::{OsmId, OsmObj, StoreObjs};
use slog_scope::info;

#[cfg(feature = "db-storage")]
use crate::settings::osm2mimir::Database;

#[cfg(feature = "db-storage")]
use slog_scope::error;

#[cfg(feature = "db-storage")]
use std::fs;

#[cfg(feature = "db-storage")]
use std::path::PathBuf;

#[cfg(feature = "db-storage")]
use std::collections::HashMap;

use std::borrow::Cow;
use std::collections::BTreeMap;

use super::street::Kind;

#[cfg(feature = "db-storage")]
use rusqlite::{Connection, DropBehavior, ToSql, NO_PARAMS};

#[cfg(feature = "db-storage")]
macro_rules! err_logger {
    ($obj:expr, $err_msg:expr) => {
        match $obj {
            Ok(x) => Some(x),
            Err(e) => {
                error!("{}: {}", $err_msg, e);
                None
            }
        }?
    };
    ($obj:expr, $err_msg:expr, $ret:expr) => {
        match $obj {
            Ok(x) => x,
            Err(e) => {
                error!("{}: {}", $err_msg, e);
                return $ret;
            }
        }
    };
}

macro_rules! get_kind {
    ($obj:expr) => {
        if $obj.is_node() {
            &0
        } else if $obj.is_way() {
            &1
        } else if $obj.is_relation() {
            &2
        } else {
            panic!("Unknown OSM object kind!")
        }
    };
}

pub trait Getter {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>>;
}

impl Getter for BTreeMap<OsmId, OsmObj> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        self.get(key).map(|x| Cow::Borrowed(x))
    }
}

#[cfg(feature = "db-storage")]
pub struct Db<'a> {
    conn: Connection,
    db_file: &'a PathBuf,
    buffer: HashMap<OsmId, OsmObj>,
    db_buffer_size: usize,
}

#[cfg(feature = "db-storage")]
impl<'a> Db<'a> {
    fn new(db_file: &'a PathBuf, db_buffer_size: usize) -> Result<Db<'a>, String> {
        let _ = fs::remove_file(db_file); // we ignore any potential error
        let conn = Connection::open(&db_file)
            .map_err(|e| format!("failed to open SQLITE connection: {}", e))?;

        conn.execute(
            "CREATE TABLE ids (
                id   INTEGER NOT NULL,
                obj  BLOB NOT NULL,
                kind INTEGER NOT NULL,
                UNIQUE(id, kind)
             )",
            NO_PARAMS,
        )
        .map_err(|e| format!("failed to create table: {}", e))?;
        Ok(Db {
            conn,
            db_file,
            buffer: HashMap::with_capacity(db_buffer_size),
            db_buffer_size,
        })
    }

    fn get_from_id(&self, id: &OsmId) -> Option<Cow<OsmObj>> {
        if let Some(obj) = self.buffer.get(id) {
            return Some(Cow::Borrowed(obj));
        }
        let mut stmt = err_logger!(
            self.conn
                .prepare("SELECT obj FROM ids WHERE id=?1 AND kind=?2"),
            "Db::get_from_id: prepare failed"
        );
        let mut iter = err_logger!(
            stmt.query(&[&id.inner_id() as &dyn ToSql, get_kind!(id)]),
            "Db::get_from_id: query_map failed"
        );
        while let Some(row) = err_logger!(iter.next(), "Db::get_from_id: next failed") {
            let obj: Vec<u8> = err_logger!(row.get(0), "Db::get_from_id: failed to get obj field");
            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "Db::for_each: serde conversion failed",
                None
            );
            return Some(Cow::Owned(obj));
        }
        None
    }

    #[allow(dead_code)]
    fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        for value in self.buffer.values() {
            f(Cow::Borrowed(value));
        }
        let mut stmt = err_logger!(
            self.conn.prepare("SELECT obj FROM ids"),
            "Db::for_each: prepare failed",
            ()
        );
        let mut rows = err_logger!(stmt.query(NO_PARAMS), "Db::for_each: query_map failed", ());
        while let Some(row) = err_logger!(rows.next(), "Db::for_each: next failed", ()) {
            let obj: Vec<u8> = err_logger!(row.get(0), "Db::for_each: failed to get obj field", ());

            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "Db::for_each: serde conversion failed",
                ()
            );
            f(Cow::Owned(obj));
        }
    }

    fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        self.buffer
            .values()
            .filter(|e| *get_kind!(e) == filter as i32)
            .for_each(|value| f(Cow::Borrowed(value)));
        let mut stmt = err_logger!(
            self.conn.prepare("SELECT obj FROM ids WHERE kind=?1"),
            "Db::for_each: prepare failed",
            ()
        );
        let mut rows = err_logger!(
            stmt.query(&[&(filter as i32) as &dyn ToSql]),
            "Db::for_each: query_map failed",
            ()
        );
        while let Some(row) = err_logger!(rows.next(), "Db::for_each: next failed", ()) {
            let obj: Vec<u8> = err_logger!(row.get(0), "Db::for_each: failed to get obj field", ());

            let obj: OsmObj = err_logger!(
                bincode::deserialize(&obj),
                "Db::for_each: serde conversion failed",
                ()
            );
            f(Cow::Owned(obj));
        }
    }

    fn flush_buffer(&mut self) {
        if self.buffer.is_empty() {
            return;
        }
        let mut tx = err_logger!(
            self.conn.transaction(),
            "Db::flush_buffer: transaction creation failed",
            ()
        );
        tx.set_drop_behavior(DropBehavior::Ignore);

        {
            let mut stmt = err_logger!(
                tx.prepare("INSERT OR IGNORE INTO ids(id, obj, kind) VALUES (?1, ?2, ?3)"),
                "Db::flush_buffer: prepare failed",
                ()
            );
            for (id, obj) in self.buffer.drain() {
                let ser_obj = match bincode::serialize(&obj) {
                    Ok(s) => s,
                    Err(e) => {
                        error!("Db::flush_buffer: failed to convert to json: {}", e);
                        continue;
                    }
                };
                let kind = get_kind!(obj);
                if let Err(e) = stmt.execute(&[&id.inner_id() as &dyn ToSql, &ser_obj, kind]) {
                    error!("Db::flush_buffer: insert failed: {}", e);
                }
            }
        }
        err_logger!(
            tx.commit(),
            "Db::flush_buffer: transaction commit failed",
            ()
        );
    }
}

#[cfg(feature = "db-storage")]
impl<'a> StoreObjs for Db<'a> {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        if self.buffer.len() >= self.db_buffer_size {
            self.flush_buffer();
        }
        self.buffer.insert(id, obj);
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        if self.buffer.contains_key(id) {
            return true;
        }
        let mut stmt = err_logger!(
            self.conn
                .prepare("SELECT id FROM ids WHERE id=?1 AND kind=?2"),
            "Db::contains_key: prepare failed",
            false
        );
        let mut iter = err_logger!(
            stmt.query(&[&id.inner_id() as &dyn ToSql, get_kind!(id)]),
            "Db::contains_key: query_map failed",
            false
        );
        err_logger!(iter.next(), "Db::contains_key: no row", false).is_some()
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Getter for Db<'a> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        self.get_from_id(key)
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Drop for Db<'a> {
    fn drop(&mut self) {
        let _ = fs::remove_file(self.db_file); // we ignore any potential error
    }
}

#[cfg(feature = "db-storage")]
pub enum ObjWrapper<'a> {
    Map(BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>),
    Db(Db<'a>),
}

#[cfg(not(feature = "db-storage"))]
pub enum ObjWrapper {
    Map(BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>),
}

#[cfg(feature = "db-storage")]
impl<'a> ObjWrapper<'a> {
    pub fn new(db: &'a Option<Database>) -> Result<ObjWrapper<'a>, Error> {
        Ok(if let Some(ref db) = db {
            info!("Running with Db storage");
            ObjWrapper::Db(Db::new(&db.file, db.buffer_size).map_err(failure::err_msg)?)
        } else {
            info!("Running with BTreeMap (RAM) storage");
            ObjWrapper::Map(BTreeMap::new())
        })
    }

    #[allow(dead_code)]
    pub fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                for value in m.values() {
                    f(Cow::Borrowed(value));
                }
            }
            ObjWrapper::Db(ref db) => db.for_each(f),
        }
    }

    pub fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                m.values()
                    .filter(|e| *get_kind!(e) == filter as i32)
                    .for_each(|value| f(Cow::Borrowed(value)));
            }
            ObjWrapper::Db(ref db) => db.for_each_filter(filter, f),
        }
    }
}

#[cfg(feature = "db-storage")]
impl<'a> Getter for ObjWrapper<'a> {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        match *self {
            ObjWrapper::Map(ref m) => m.get(key).map(|x| Cow::Borrowed(x)),
            ObjWrapper::Db(ref db) => db.get(key),
        }
    }
}

#[cfg(feature = "db-storage")]
impl<'a> StoreObjs for ObjWrapper<'a> {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        match *self {
            ObjWrapper::Map(ref mut m) => {
                m.insert(id, obj);
            }
            ObjWrapper::Db(ref mut db) => db.insert(id, obj),
        }
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        match *self {
            ObjWrapper::Map(ref m) => m.contains_key(id),
            ObjWrapper::Db(ref db) => db.contains_key(id),
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl ObjWrapper {
    pub fn new() -> Result<ObjWrapper, Error> {
        info!("Running with BTreeMap (RAM) storage");
        Ok(ObjWrapper::Map(BTreeMap::new()))
    }

    #[allow(dead_code)]
    pub fn for_each<F: FnMut(Cow<OsmObj>)>(&self, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                for value in m.values() {
                    f(Cow::Borrowed(value));
                }
            }
        }
    }

    pub fn for_each_filter<F: FnMut(Cow<OsmObj>)>(&self, filter: Kind, mut f: F) {
        match *self {
            ObjWrapper::Map(ref m) => {
                m.values()
                    .filter(|e| *get_kind!(e) == filter as i32)
                    .for_each(|value| f(Cow::Borrowed(value)));
            }
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl Getter for ObjWrapper {
    fn get(&self, key: &OsmId) -> Option<Cow<OsmObj>> {
        match *self {
            ObjWrapper::Map(ref m) => m.get(key).map(|x| Cow::Borrowed(x)),
        }
    }
}

#[cfg(not(feature = "db-storage"))]
impl StoreObjs for ObjWrapper {
    fn insert(&mut self, id: OsmId, obj: OsmObj) {
        match *self {
            ObjWrapper::Map(ref mut m) => {
                m.insert(id, obj);
            }
        }
    }

    fn contains_key(&self, id: &OsmId) -> bool {
        match *self {
            ObjWrapper::Map(ref m) => m.contains_key(id),
        }
    }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
    let href:String = vec!["data:text/plain;",&filecontent].into_iter().collect();
    a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
}

pub fn render() -> seed::dom_types::Node<Msg> {

    div![
        h1!["The Fermat Numbers"],
        br![],
        br![],
        br![],
        //todo: replace with rust elements
        El::from_html("

 	No.	Fermat	Digits	Prime / Factors	Download

 	11	22048+1		P27567 × 974849 × 167988556341760475137 × 3560841906445833920513 × P564

 	10	21024+1		45592577 × 6487031809 × 4659775785220018543264560743076778192897 × P252

 	9	2512+1	155	2424833 × 7455602825647884208337395736200454918783366342657 × P99	TXT

 	8	2256+1	78	1238926361552897 × P62	TXT

 	7	2128+1	39	59649589127497217 × 5704689200685129054721	TXT

 	6	264+1	20	274177 × 67280421310721	TXT

 	5	232+1	10	P116 × 6700417	TXT

 	4	216+1	5	P6543	TXT

 	3	28+1	3	P55	TXT

 	2	24+1	2	P7	TXT

 	1	22+1	1	P3	TXT

 	0	21+1	1	P2	TXT

"),
    ]
}<commit_msg>Added fermat_utils mod<commit_after>use seed::prelude::*;
use crate::Msg;

mod fermat_utils {
    use seed::prelude::*;
    use crate::Msg;

    pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain;",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {

    div![
        h1!["The Fermat Numbers"],
        br![],
        br![],
        br![],
        //todo: replace with rust elements
        El::from_html("

 	No.	Fermat	Digits	Prime / Factors	Download

 	11	22048+1		P27567 × 974849 × 167988556341760475137 × 3560841906445833920513 × P564

 	10	21024+1		45592577 × 6487031809 × 4659775785220018543264560743076778192897 × P252

 	9	2512+1	155	2424833 × 7455602825647884208337395736200454918783366342657 × P99	TXT

 	8	2256+1	78	1238926361552897 × P62	TXT

 	7	2128+1	39	59649589127497217 × 5704689200685129054721	TXT

 	6	264+1	20	274177 × 67280421310721	TXT

 	5	232+1	10	P116 × 6700417	TXT

 	4	216+1	5	P6543	TXT

 	3	28+1	3	P55	TXT

 	2	24+1	2	P7	TXT

 	1	22+1	1	P3	TXT

 	0	21+1	1	P2	TXT

"),
    ]
}<|endoftext|>


<commit_before>use alloc::rc::Rc;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use common::debug;
use common::elf::Elf;
use common::memory;

use scheduler;
use scheduler::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, contexts_ptr, Context, ContextFile, ContextMemory};

use schemes::Url;

/// Excecute an excecutable
// TODO: Modify current context, take current stdio
pub fn execute(url: Url, mut args: Vec<String>) {
    unsafe {
        let reenable = scheduler::start_no_ints();

        let context_ptr: *mut Context = if let Some(mut current) = Context::current_mut() {
            current.deref_mut()
        } else {
            0 as *mut Context
        };

        scheduler::end_no_ints(reenable);

        if context_ptr as usize > 0 {
            Context::spawn("kexec ".to_string() + &url.string, box move || {
                if let Some(mut resource) = url.open() {
                    let mut vec: Vec<u8> = Vec::new();
                    resource.read_to_end(&mut vec);

                    let executable = Elf::from_data(vec.as_ptr() as usize);
                    let entry = executable.entry();
                    let mut memory = Vec::new();
                    for segment in executable.load_segment().iter() {
                        let virtual_address = segment.vaddr as usize;
                        let virtual_size = segment.mem_len as usize;
                        let physical_address = memory::alloc(virtual_size);

                        if physical_address > 0 {
                            // Copy progbits
                            ::memcpy(physical_address as *mut u8,
                                     (executable.data + segment.off as usize) as *const u8,
                                     segment.file_len as usize);
                            // Zero bss
                            ::memset((physical_address + segment.file_len as usize) as *mut u8,
                                     0,
                                     segment.mem_len as usize - segment.file_len as usize);

                             memory.push(ContextMemory {
                                 physical_address: physical_address,
                                 virtual_address: virtual_address,
                                 virtual_size: virtual_size,
                                 writeable: segment.flags & 2 == 2
                             });
                        }
                    }

                    if entry > 0 && ! memory.is_empty() {
                        args.insert(0, url.to_string());

                        let mut context_args: Vec<usize> = Vec::new();
                        context_args.push(0); // ENVP
                        context_args.push(0); // ARGV NULL
                        let mut argc = 0;
                        for i in 0..args.len() {
                            if let Some(arg) = args.get(args.len() - i - 1) {
                                context_args.push(arg.as_ptr() as usize);
                                argc += 1;
                            }
                        }
                        context_args.push(argc);

                        let reenable = scheduler::start_no_ints();

                        let context = &mut * context_ptr;

                        let mut files: Vec<ContextFile> = Vec::new();
                        for file in (*context.files.get()).iter() {
                            if let Some(resource) = file.resource.dup() {
                                files.push(ContextFile {
                                    fd: file.fd,
                                    resource: resource,
                                });
                            }
                        }

                        context.name = url.to_string();

                        context.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

                        context.stack = Some(ContextMemory {
                            physical_address: memory::alloc(CONTEXT_STACK_SIZE),
                            virtual_address: CONTEXT_STACK_ADDR,
                            virtual_size: CONTEXT_STACK_SIZE,
                            writeable: true
                        });

                        context.args = Rc::new(UnsafeCell::new(args));
                        context.cwd = Rc::new(UnsafeCell::new((*context.cwd.get()).clone()));
                        context.memory = Rc::new(UnsafeCell::new(memory));
                        context.files = Rc::new(UnsafeCell::new(files));

                        let user_sp = if let Some(ref stack) = context.stack {
                            let mut sp = stack.physical_address + stack.virtual_size - 128;
                            for arg in context_args.iter() {
                                sp -= mem::size_of::<usize>();
                                ptr::write(sp as *mut usize, *arg);
                            }
                            sp - stack.physical_address + stack.virtual_address
                        } else {
                            0
                        };

                        context.push(0x20 | 3);
                        context.push(user_sp);
                        context.push(1 << 9);
                        context.push(0x18 | 3);
                        context.push(entry);
                        context.push(context_userspace as usize);

                        scheduler::end_no_ints(reenable);
                    } else {
                        debug!("{}: Invalid memory or entry\n", url.string);
                    }
                } else {
                    debug!("{}: Failed to open\n", url.string);
                }
            });

            loop {
                context_switch(false);
            }
        }
    }
}
<commit_msg>Remove unnecessary file dup<commit_after>use alloc::rc::Rc;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use common::debug;
use common::elf::Elf;
use common::memory;

use scheduler;
use scheduler::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, contexts_ptr, Context, ContextFile, ContextMemory};

use schemes::Url;

/// Excecute an excecutable
// TODO: Modify current context, take current stdio
pub fn execute(url: Url, mut args: Vec<String>) {
    unsafe {
        let reenable = scheduler::start_no_ints();

        let context_ptr: *mut Context = if let Some(mut current) = Context::current_mut() {
            current.deref_mut()
        } else {
            0 as *mut Context
        };

        scheduler::end_no_ints(reenable);

        if context_ptr as usize > 0 {
            Context::spawn("kexec ".to_string() + &url.string, box move || {
                if let Some(mut resource) = url.open() {
                    let mut vec: Vec<u8> = Vec::new();
                    resource.read_to_end(&mut vec);

                    let executable = Elf::from_data(vec.as_ptr() as usize);
                    let entry = executable.entry();
                    let mut memory = Vec::new();
                    for segment in executable.load_segment().iter() {
                        let virtual_address = segment.vaddr as usize;
                        let virtual_size = segment.mem_len as usize;
                        let physical_address = memory::alloc(virtual_size);

                        if physical_address > 0 {
                            // Copy progbits
                            ::memcpy(physical_address as *mut u8,
                                     (executable.data + segment.off as usize) as *const u8,
                                     segment.file_len as usize);
                            // Zero bss
                            ::memset((physical_address + segment.file_len as usize) as *mut u8,
                                     0,
                                     segment.mem_len as usize - segment.file_len as usize);

                             memory.push(ContextMemory {
                                 physical_address: physical_address,
                                 virtual_address: virtual_address,
                                 virtual_size: virtual_size,
                                 writeable: segment.flags & 2 == 2
                             });
                        }
                    }

                    if entry > 0 && ! memory.is_empty() {
                        args.insert(0, url.to_string());

                        let mut context_args: Vec<usize> = Vec::new();
                        context_args.push(0); // ENVP
                        context_args.push(0); // ARGV NULL
                        let mut argc = 0;
                        for i in 0..args.len() {
                            if let Some(arg) = args.get(args.len() - i - 1) {
                                context_args.push(arg.as_ptr() as usize);
                                argc += 1;
                            }
                        }
                        context_args.push(argc);

                        let reenable = scheduler::start_no_ints();

                        let context = &mut * context_ptr;

                        context.name = url.to_string();

                        context.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

                        context.stack = Some(ContextMemory {
                            physical_address: memory::alloc(CONTEXT_STACK_SIZE),
                            virtual_address: CONTEXT_STACK_ADDR,
                            virtual_size: CONTEXT_STACK_SIZE,
                            writeable: true
                        });

                        context.args = Rc::new(UnsafeCell::new(args));
                        context.cwd = Rc::new(UnsafeCell::new((*context.cwd.get()).clone()));
                        context.memory = Rc::new(UnsafeCell::new(memory));

                        let user_sp = if let Some(ref stack) = context.stack {
                            let mut sp = stack.physical_address + stack.virtual_size - 128;
                            for arg in context_args.iter() {
                                sp -= mem::size_of::<usize>();
                                ptr::write(sp as *mut usize, *arg);
                            }
                            sp - stack.physical_address + stack.virtual_address
                        } else {
                            0
                        };

                        context.push(0x20 | 3);
                        context.push(user_sp);
                        context.push(1 << 9);
                        context.push(0x18 | 3);
                        context.push(entry);
                        context.push(context_userspace as usize);

                        scheduler::end_no_ints(reenable);
                    } else {
                        debug!("{}: Invalid memory or entry\n", url.string);
                    }
                } else {
                    debug!("{}: Failed to open\n", url.string);
                }
            });

            loop {
                context_switch(false);
            }
        }
    }
}
<|endoftext|>


<commit_before>use tokenizer::TomlFragment;

#[derive(PartialEq, Debug)]
pub enum AstFragment<'a> {
    Boolean(bool),
    Whitespace(&'a str),
    Array(Vec<AstFragment<'a>>),
    Comma,
}

#[derive(PartialEq, Debug)]
pub struct ParseResult<'a> {
    pub number_of_consumed_tokens : usize,

    pub parse_result : Vec<AstFragment<'a>>,
}

pub fn parse_token<'a>(tokens: &'a[TomlFragment]) -> Result<ParseResult<'a>, &'a str> {
    let token = &tokens[0];

    let ast_fragment =
        match token {
            &TomlFragment::Boolean("true") => AstFragment::Boolean(true),
            &TomlFragment::Boolean("false") => AstFragment::Boolean(false),
            &TomlFragment::Whitespace(s) => AstFragment::Whitespace(s),
            &TomlFragment::Comma => AstFragment::Comma,
            &TomlFragment::BracketOpen => return parse_array(tokens),
            _ => return Err("not implemented"),
        };

    Ok(ParseResult { number_of_consumed_tokens: 1, parse_result: vec![ast_fragment] })
}

pub fn parse_array<'a>(tokens: &'a[TomlFragment]) -> Result<ParseResult<'a>, &'a str> {
    let mut elements = Vec::new();

    let mut seen_opening_bracket  = false;

    let mut index = 0;

    let token_count = tokens.iter().count();

    while index < token_count {
        let token = &tokens[index];
        match token {
            &TomlFragment::BracketOpen =>
                if seen_opening_bracket {
                    return Err("Recursive arrays not implemented");
                } else {
                    seen_opening_bracket = true;
                    index = index + 1;
                },
            &TomlFragment::BracketClose =>
                if seen_opening_bracket {
                    let result = vec![AstFragment::Array(elements)];
                    return Ok(ParseResult { number_of_consumed_tokens: index + 1, parse_result: result });
                } else {
                    return Err("Too many closing brackets");
                },
            _ =>
                match parse_token(&tokens[index..]) {
                    Ok(result) => {
                            elements.extend(result.parse_result);
                            index = index + result.number_of_consumed_tokens;
                        },
                    Err(msg) => return Err(msg),
                },
        }
    }

    Err("Unterminated array")
}

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

    #[test]
    fn parse_fragment_whitespace() {
        let input = vec![TomlFragment::Whitespace("   ")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Whitespace("   ")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_boolean_true() {
        let input = vec![TomlFragment::Boolean("true")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Boolean(true)]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_boolean_false() {
        let input = vec![TomlFragment::Boolean("false")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Boolean(false)]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_empty_array() {
        let input = vec![TomlFragment::BracketOpen, TomlFragment::BracketClose];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 2,
                    parse_result: vec![AstFragment::Array(Vec::new())]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_empty_array_whitespace() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Whitespace(" "),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Whitespace(" ")])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_single_element_array_bool_true() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("true"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Boolean(true)])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_single_element_array_bool_false() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("false"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Boolean(false)])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_two_element_array_1() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("true"),
            TomlFragment::Comma,
            TomlFragment::Boolean("false"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 5,
                    parse_result:
                        vec![
                            AstFragment::Array(
                                vec![
                                    AstFragment::Boolean(true),
                                    AstFragment::Comma,
                                    AstFragment::Boolean(false)
                                ])
                        ]
                });

        assert_eq!(expected, parse_array(&input));
    }
}
<commit_msg>Parse simple integers<commit_after>use tokenizer::TomlFragment;

#[derive(PartialEq, Debug)]
pub enum AstFragment<'a> {
    Boolean(bool),
    Whitespace(&'a str),
    Array(Vec<AstFragment<'a>>),
    Comma,
    Integer(i64, &'a str),
}

#[derive(PartialEq, Debug)]
pub struct ParseResult<'a> {
    pub number_of_consumed_tokens : usize,

    pub parse_result : Vec<AstFragment<'a>>,
}

pub fn parse_token<'a>(tokens: &'a[TomlFragment]) -> Result<ParseResult<'a>, &'a str> {
    let token = &tokens[0];

    let ast_fragment =
        match token {
            &TomlFragment::Boolean("true") => AstFragment::Boolean(true),
            &TomlFragment::Boolean("false") => AstFragment::Boolean(false),
            &TomlFragment::Whitespace(s) => AstFragment::Whitespace(s),
            &TomlFragment::Comma => AstFragment::Comma,
            &TomlFragment::BracketOpen => return parse_array(tokens),
            &TomlFragment::Integer(s) => AstFragment::Integer(s.parse::<i64>().ok().unwrap(), s),
            _ => return Err("not implemented"),
        };

    Ok(ParseResult { number_of_consumed_tokens: 1, parse_result: vec![ast_fragment] })
}

pub fn parse_array<'a>(tokens: &'a[TomlFragment]) -> Result<ParseResult<'a>, &'a str> {
    let mut elements = Vec::new();

    let mut seen_opening_bracket  = false;

    let mut index = 0;

    let token_count = tokens.iter().count();

    while index < token_count {
        let token = &tokens[index];
        match token {
            &TomlFragment::BracketOpen =>
                if seen_opening_bracket {
                    return Err("Recursive arrays not implemented");
                } else {
                    seen_opening_bracket = true;
                    index = index + 1;
                },
            &TomlFragment::BracketClose =>
                if seen_opening_bracket {
                    let result = vec![AstFragment::Array(elements)];
                    return Ok(ParseResult { number_of_consumed_tokens: index + 1, parse_result: result });
                } else {
                    return Err("Too many closing brackets");
                },
            _ =>
                match parse_token(&tokens[index..]) {
                    Ok(result) => {
                            elements.extend(result.parse_result);
                            index = index + result.number_of_consumed_tokens;
                        },
                    Err(msg) => return Err(msg),
                },
        }
    }

    Err("Unterminated array")
}

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

    #[test]
    fn parse_fragment_whitespace() {
        let input = vec![TomlFragment::Whitespace("   ")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Whitespace("   ")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_boolean_true() {
        let input = vec![TomlFragment::Boolean("true")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Boolean(true)]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_boolean_false() {
        let input = vec![TomlFragment::Boolean("false")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Boolean(false)]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_integer_0() {
        let input = vec![TomlFragment::Integer("0")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Integer(0, "0")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_integer_1() {
        let input = vec![TomlFragment::Integer("1")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Integer(1, "1")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_integer_min() {
        let input = vec![TomlFragment::Integer("-9223372036854775808")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Integer(-9223372036854775808, "-9223372036854775808")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_fragment_integer_max() {
        let input = vec![TomlFragment::Integer("9223372036854775807")];
        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 1,
                    parse_result: vec![AstFragment::Integer(9223372036854775807, "9223372036854775807")]
                });

        assert_eq!(expected, parse_token(&input));
    }

    #[test]
    fn parse_empty_array() {
        let input = vec![TomlFragment::BracketOpen, TomlFragment::BracketClose];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 2,
                    parse_result: vec![AstFragment::Array(Vec::new())]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_empty_array_whitespace() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Whitespace(" "),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Whitespace(" ")])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_single_element_array_bool_true() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("true"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Boolean(true)])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_single_element_array_bool_false() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("false"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 3,
                    parse_result: vec![AstFragment::Array(vec![AstFragment::Boolean(false)])]
                });

        assert_eq!(expected, parse_array(&input));
    }

    #[test]
    fn parse_two_element_array_1() {
        let input = vec![
            TomlFragment::BracketOpen,
            TomlFragment::Boolean("true"),
            TomlFragment::Comma,
            TomlFragment::Boolean("false"),
            TomlFragment::BracketClose
        ];

        let expected =
            Ok(
                ParseResult {
                    number_of_consumed_tokens: 5,
                    parse_result:
                        vec![
                            AstFragment::Array(
                                vec![
                                    AstFragment::Boolean(true),
                                    AstFragment::Comma,
                                    AstFragment::Boolean(false)
                                ])
                        ]
                });

        assert_eq!(expected, parse_array(&input));
    }
}
<|endoftext|>


<commit_before>// TODO: Could we leverage SIMD here??

#[cfg(test)]
mod spec_tests;

use ppu::control_register::ControlRegister;
use ppu::palette::{Color, PALETTE};
use ppu::vram::Vram;

#[derive(Default)]
pub struct BackgroundRenderer {
    palettes: [Color; 16],
    pattern_low_shift_register: u16,
    pattern_high_shift_register: u16,
    palette_low_bit_shift_register: u16,
    palette_high_bit_shift_register: u16,
    attr_latch: u8,
    nametable_latch: u8,
    pattern_low_latch: u8,
    pattern_high_latch: u8,
}

impl BackgroundRenderer {
    pub fn update_palettes<V: Vram>(&mut self, vram: &V) {
        let bg = vram.read(0x3f00) as usize;
        self.palettes = [
            PALETTE[bg],
            PALETTE[vram.read(0x3f01) as usize],
            PALETTE[vram.read(0x3f02) as usize],
            PALETTE[vram.read(0x3f03) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f05) as usize],
            PALETTE[vram.read(0x3f06) as usize],
            PALETTE[vram.read(0x3f07) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f09) as usize],
            PALETTE[vram.read(0x3f0a) as usize],
            PALETTE[vram.read(0x3f0b) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f0d) as usize],
            PALETTE[vram.read(0x3f0e) as usize],
            PALETTE[vram.read(0x3f0f) as usize],
        ];
    }

    pub fn current_pixel(&self, fine_x: u8) -> (u8, Color) {
        let pattern_low = self.pattern_low_shift_register << fine_x;
        let pattern_high = self.pattern_high_shift_register << fine_x;
        let pixel = (((pattern_high & 0x8000) >> 14) | ((pattern_low & 0x8000) >> 15)) as u8 & 0b11;

        let palette_low = self.palette_low_bit_shift_register << fine_x;
        let palette_high = self.palette_high_bit_shift_register << fine_x;
        let palette = (((palette_high & 0x8000) >> 12) | ((palette_low & 0x8000) >> 13)) as u8;
        let palette_index = (palette | pixel) as usize;
        let color = self.palettes[palette_index];
        (pixel, color)
    }

    pub fn fill_shift_registers(&mut self, v: u16) {
        self.pattern_low_shift_register |= self.pattern_low_latch as u16;
        self.pattern_high_shift_register |= self.pattern_high_latch as u16;
        let (palette_low, palette_high) = Self::palette_shift_bytes(v, self.attr_latch);
        self.palette_low_bit_shift_register |= palette_low as u16;
        self.palette_high_bit_shift_register |= palette_high as u16;
    }

    fn palette_shift_bytes(v: u16, attr_byte: u8) -> (u8, u8) {
        // Second bit of coarse x and coarse y determine which bits get loaded into the shift
        // registers.

        // Intentionally shift each bit one too few to effectively multiply the OR'd result by two.
        // This will give us the amount to shift right by, selecting the correct two attribute bits.
        let x_component = v & 0b10;
        let y_component = (v >> 4) & 0b100;
        let shift = (y_component | x_component) as usize;
        let palette_nibble = (attr_byte >> shift) & 0b11;

        // Return (low bits, high bits)
        ((palette_nibble & 1) * 255, (palette_nibble >> 1) * 255)
    }

    pub fn tick_shifters(&mut self) {
        self.pattern_low_shift_register <<= 1;
        self.pattern_high_shift_register <<= 1;
        self.palette_low_bit_shift_register <<= 1;
        self.palette_high_bit_shift_register <<= 1;
    }

    // TODO: Tests
    pub fn fetch_attribute_byte<V: Vram>(&mut self, vram: &V) {
        let v = vram.addr();
        let attribute_address = 0x23C0 | (v & 0x0C00) | ((v >> 4) & 0x38) | ((v >> 2) & 0x07);
        self.attr_latch = vram.read(attribute_address);
    }

    // TODO: Tests
    pub fn fetch_nametable_byte<V: Vram>(&mut self, vram: &V) {
        let nametable_address = 0x2000 | (vram.addr() & 0x0FFF);
        self.nametable_latch = vram.read(nametable_address);
    }

    // TODO: Tests
    pub fn fetch_pattern_low_byte<V: Vram>(&mut self, vram: &V, control: ControlRegister) {
        let v = vram.addr();
        let pattern_addr = Self::pattern_offset(v, self.nametable_latch, control, true);
        self.pattern_low_latch = vram.read(pattern_addr);
    }

    // TODO: Tests
    pub fn fetch_pattern_high_byte<V: Vram>(&mut self, vram: &V, control: ControlRegister) {
        let v = vram.addr();
        let pattern_addr = Self::pattern_offset(v, self.nametable_latch, control, false);
        self.pattern_high_latch = vram.read(pattern_addr);
    }

    // TODO: Tests
    fn pattern_offset(
        v: u16,
        nametable_byte: u8,
        control: ControlRegister,
        is_lower_plane: bool,
    ) -> u16 {
        let fine_y = (v >> 12) & 0b111;
        let plane = if is_lower_plane { 0 } else { 0b1000 };
        let column_and_row = (nametable_byte as u16) << 4;
        control.background_pattern_table_base() | column_and_row | plane | fine_y
    }
}
<commit_msg>Pack all shift registers into an array<commit_after>// TODO: Could we leverage SIMD here??

#[cfg(test)]
mod spec_tests;

use ppu::control_register::ControlRegister;
use ppu::palette::{Color, PALETTE};
use ppu::vram::Vram;

#[derive(Default)]
pub struct BackgroundRenderer {
    palettes: [Color; 16],
    shift_registers: [u16; 4], // [pattern_low, pattern_high, palette_low, palette_high]
    attr_latch: u8,
    nametable_latch: u8,
    pattern_low_latch: u8,
    pattern_high_latch: u8,
}

impl BackgroundRenderer {
    pub fn update_palettes<V: Vram>(&mut self, vram: &V) {
        let bg = vram.read(0x3f00) as usize;
        self.palettes = [
            PALETTE[bg],
            PALETTE[vram.read(0x3f01) as usize],
            PALETTE[vram.read(0x3f02) as usize],
            PALETTE[vram.read(0x3f03) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f05) as usize],
            PALETTE[vram.read(0x3f06) as usize],
            PALETTE[vram.read(0x3f07) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f09) as usize],
            PALETTE[vram.read(0x3f0a) as usize],
            PALETTE[vram.read(0x3f0b) as usize],
            PALETTE[bg],
            PALETTE[vram.read(0x3f0d) as usize],
            PALETTE[vram.read(0x3f0e) as usize],
            PALETTE[vram.read(0x3f0f) as usize],
        ];
    }

    pub fn current_pixel(&self, fine_x: u8) -> (u8, Color) {
        let pattern_low = self.shift_registers[0] << fine_x;
        let pattern_high = self.shift_registers[1] << fine_x;
        let palette_low = self.shift_registers[2] << fine_x;
        let palette_high = self.shift_registers[3] << fine_x;
        let pixel = (((pattern_high & 0x8000) >> 14) | ((pattern_low & 0x8000) >> 15)) as u8 & 0b11;

        let palette = (((palette_high & 0x8000) >> 12) | ((palette_low & 0x8000) >> 13)) as u8;
        let palette_index = (palette | pixel) as usize;
        let color = self.palettes[palette_index];
        (pixel, color)
    }

    pub fn fill_shift_registers(&mut self, v: u16) {
        let (palette_low, palette_high) = Self::palette_shift_bytes(v, self.attr_latch);
        self.shift_registers[0] |= self.pattern_low_latch as u16;
        self.shift_registers[1] |= self.pattern_high_latch as u16;
        self.shift_registers[2] |= palette_low as u16;
        self.shift_registers[3] |= palette_high as u16;
    }

    fn palette_shift_bytes(v: u16, attr_byte: u8) -> (u8, u8) {
        // Second bit of coarse x and coarse y determine which bits get loaded into the shift
        // registers.

        // Intentionally shift each bit one too few to effectively multiply the OR'd result by two.
        // This will give us the amount to shift right by, selecting the correct two attribute bits.
        let x_component = v & 0b10;
        let y_component = (v >> 4) & 0b100;
        let shift = (y_component | x_component) as usize;
        let palette_nibble = (attr_byte >> shift) & 0b11;

        // Return (low bits, high bits)
        ((palette_nibble & 1) * 255, (palette_nibble >> 1) * 255)
    }

    pub fn tick_shifters(&mut self) {
        self.shift_registers[0] <<= 1;
        self.shift_registers[1] <<= 1;
        self.shift_registers[2] <<= 1;
        self.shift_registers[3] <<= 1;
    }

    // TODO: Tests
    pub fn fetch_attribute_byte<V: Vram>(&mut self, vram: &V) {
        let v = vram.addr();
        let attribute_address = 0x23C0 | (v & 0x0C00) | ((v >> 4) & 0x38) | ((v >> 2) & 0x07);
        self.attr_latch = vram.read(attribute_address);
    }

    // TODO: Tests
    pub fn fetch_nametable_byte<V: Vram>(&mut self, vram: &V) {
        let nametable_address = 0x2000 | (vram.addr() & 0x0FFF);
        self.nametable_latch = vram.read(nametable_address);
    }

    // TODO: Tests
    pub fn fetch_pattern_low_byte<V: Vram>(&mut self, vram: &V, control: ControlRegister) {
        let v = vram.addr();
        let pattern_addr = Self::pattern_offset(v, self.nametable_latch, control, true);
        self.pattern_low_latch = vram.read(pattern_addr);
    }

    // TODO: Tests
    pub fn fetch_pattern_high_byte<V: Vram>(&mut self, vram: &V, control: ControlRegister) {
        let v = vram.addr();
        let pattern_addr = Self::pattern_offset(v, self.nametable_latch, control, false);
        self.pattern_high_latch = vram.read(pattern_addr);
    }

    // TODO: Tests
    fn pattern_offset(
        v: u16,
        nametable_byte: u8,
        control: ControlRegister,
        is_lower_plane: bool,
    ) -> u16 {
        let fine_y = (v >> 12) & 0b111;
        let plane = if is_lower_plane { 0 } else { 0b1000 };
        let column_and_row = (nametable_byte as u16) << 4;
        control.background_pattern_table_base() | column_and_row | plane | fine_y
    }
}
<|endoftext|>


<commit_before>use std::cmp;

use crate::ich::StableHashingContext;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{builtin, Level, Lint, LintId};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
pub enum LintSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),

    /// Lint level was set by a command-line flag.
    /// The provided `Level` is the level specified on the command line -
    /// the actual level may be lower due to `--cap-lints`
    CommandLine(Symbol, Level),
}

impl LintSource {
    pub fn name(&self) -> Symbol {
        match *self {
            LintSource::Default => symbol::kw::Default,
            LintSource::Node(name, _, _) => name,
            LintSource::CommandLine(name, _) => name,
        }
    }

    pub fn span(&self) -> Span {
        match *self {
            LintSource::Default => DUMMY_SP,
            LintSource::Node(_, span, _) => span,
            LintSource::CommandLine(_, _) => DUMMY_SP,
        }
    }
}

pub type LevelSource = (Level, LintSource);

pub struct LintLevelSets {
    pub list: Vec<LintSet>,
    pub lint_cap: Level,
}

pub enum LintSet {
    CommandLine {
        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
        // flag.
        specs: FxHashMap<LintId, LevelSource>,
    },

    Node {
        specs: FxHashMap<LintId, LevelSource>,
        parent: u32,
    },
}

impl LintLevelSets {
    pub fn new() -> Self {
        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
    }

    pub fn get_lint_level(
        &self,
        lint: &'static Lint,
        idx: u32,
        aux: Option<&FxHashMap<LintId, LevelSource>>,
        sess: &Session,
    ) -> LevelSource {
        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);

        // If `level` is none then we actually assume the default level for this
        // lint.
        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));

        // If we're about to issue a warning, check at the last minute for any
        // directives against the warnings "lint". If, for example, there's an
        // `allow(warnings)` in scope then we want to respect that instead.
        if level == Level::Warn {
            let (warnings_level, warnings_src) =
                self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
            if let Some(configured_warning_level) = warnings_level {
                if configured_warning_level != Level::Warn {
                    level = configured_warning_level;
                    src = warnings_src;
                }
            }
        }

        // Ensure that we never exceed the `--cap-lints` argument.
        level = cmp::min(level, self.lint_cap);

        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
            // Ensure that we never exceed driver level.
            level = cmp::min(*driver_level, level);
        }

        (level, src)
    }

    pub fn get_lint_id_level(
        &self,
        id: LintId,
        mut idx: u32,
        aux: Option<&FxHashMap<LintId, LevelSource>>,
    ) -> (Option<Level>, LintSource) {
        if let Some(specs) = aux {
            if let Some(&(level, src)) = specs.get(&id) {
                return (Some(level), src);
            }
        }
        loop {
            match self.list[idx as usize] {
                LintSet::CommandLine { ref specs } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    return (None, LintSource::Default);
                }
                LintSet::Node { ref specs, parent } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    idx = parent;
                }
            }
        }
    }
}

pub struct LintLevelMap {
    pub sets: LintLevelSets,
    pub id_to_set: FxHashMap<HirId, u32>,
}

impl LintLevelMap {
    /// If the `id` was previously registered with `register_id` when building
    /// this `LintLevelMap` this returns the corresponding lint level and source
    /// of the lint level for the lint provided.
    ///
    /// If the `id` was not previously registered, returns `None`. If `None` is
    /// returned then the parent of `id` should be acquired and this function
    /// should be called again.
    pub fn level_and_source(
        &self,
        lint: &'static Lint,
        id: HirId,
        session: &Session,
    ) -> Option<LevelSource> {
        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let LintLevelMap { ref sets, ref id_to_set } = *self;

        id_to_set.hash_stable(hcx, hasher);

        let LintLevelSets { ref list, lint_cap } = *sets;

        lint_cap.hash_stable(hcx, hasher);

        hcx.while_hashing_spans(true, |hcx| {
            list.len().hash_stable(hcx, hasher);

            // We are working under the assumption here that the list of
            // lint-sets is built in a deterministic order.
            for lint_set in list {
                ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);

                match *lint_set {
                    LintSet::CommandLine { ref specs } => {
                        specs.hash_stable(hcx, hasher);
                    }
                    LintSet::Node { ref specs, parent } => {
                        specs.hash_stable(hcx, hasher);
                        parent.hash_stable(hcx, hasher);
                    }
                }
            }
        })
    }
}

pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>);

impl<'a> LintDiagnosticBuilder<'a> {
    /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
    pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
        self.0.set_primary_message(msg);
        self.0
    }

    /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
    pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> {
        LintDiagnosticBuilder(err)
    }
}

pub fn struct_lint_level<'s, 'd>(
    sess: &'s Session,
    lint: &'static Lint,
    level: Level,
    src: LintSource,
    span: Option<MultiSpan>,
    decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
) {
    // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
    // the "real" work.
    fn struct_lint_level_impl(
        sess: &'s Session,
        lint: &'static Lint,
        level: Level,
        src: LintSource,
        span: Option<MultiSpan>,
        decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
    ) {
        // Check for future incompatibility lints and issue a stronger warning.
        let lint_id = LintId::of(lint);
        let future_incompatible = lint.future_incompatible;

        let has_future_breakage =
            future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());

        let mut err = match (level, span) {
            (Level::Allow, span) => {
                if has_future_breakage {
                    if let Some(span) = span {
                        sess.struct_span_allow(span, "")
                    } else {
                        sess.struct_allow("")
                    }
                } else {
                    return;
                }
            }
            (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
            (Level::Warn, None) => sess.struct_warn(""),
            (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
            (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
        };

        // If this code originates in a foreign macro, aka something that this crate
        // did not itself author, then it's likely that there's nothing this crate
        // can do about it. We probably want to skip the lint entirely.
        if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
            // Any suggestions made here are likely to be incorrect, so anything we
            // emit shouldn't be automatically fixed by rustfix.
            err.allow_suggestions(false);

            // If this is a future incompatible lint it'll become a hard error, so
            // we have to emit *something*. Also, if this lint occurs in the
            // expansion of a macro from an external crate, allow individual lints
            // to opt-out from being reported.
            if future_incompatible.is_none() && !lint.report_in_external_macro {
                err.cancel();
                // Don't continue further, since we don't want to have
                // `diag_span_note_once` called for a diagnostic that isn't emitted.
                return;
            }
        }

        let name = lint.name_lower();
        match src {
            LintSource::Default => {
                sess.diag_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    &format!("`#[{}({})]` on by default", level.as_str(), name),
                );
            }
            LintSource::CommandLine(lint_flag_val, orig_level) => {
                let flag = match orig_level {
                    Level::Warn => "-W",
                    Level::Deny => "-D",
                    Level::Forbid => "-F",
                    Level::Allow => "-A",
                };
                let hyphen_case_lint_name = name.replace("_", "-");
                if lint_flag_val.as_str() == name {
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "requested on the command line with `{} {}`",
                            flag, hyphen_case_lint_name
                        ),
                    );
                } else {
                    let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`{} {}` implied by `{} {}`",
                            flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
                        ),
                    );
                }
            }
            LintSource::Node(lint_attr_name, src, reason) => {
                if let Some(rationale) = reason {
                    err.note(&rationale.as_str());
                }
                sess.diag_span_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    src,
                    "the lint level is defined here",
                );
                if lint_attr_name.as_str() != name {
                    let level_str = level.as_str();
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`#[{}({})]` implied by `#[{}({})]`",
                            level_str, name, level_str, lint_attr_name
                        ),
                    );
                }
            }
        }

        err.code(DiagnosticId::Lint { name, has_future_breakage });

        if let Some(future_incompatible) = future_incompatible {
            const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
                 it will become a hard error";

            let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
                "once this method is added to the standard library, \
                 the ambiguity may cause an error or change in behavior!"
                    .to_owned()
            } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
                "this borrowing pattern was not meant to be accepted, \
                 and may become a hard error in the future"
                    .to_owned()
            } else if let Some(edition) = future_incompatible.edition {
                format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
            } else {
                format!("{} in a future release!", STANDARD_MESSAGE)
            };
            let citation = format!("for more information, see {}", future_incompatible.reference);
            err.warn(&explanation);
            err.note(&citation);
        }

        // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
        decorate(LintDiagnosticBuilder::new(err));
    }
    struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
}

/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
    let expn_data = span.ctxt().outer_expn_data();
    match expn_data.kind {
        ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => {
            false
        }
        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
        ExpnKind::Macro(MacroKind::Bang, _) => {
            // Dummy span for the `def_site` means it's an external macro.
            expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
        }
        ExpnKind::Macro { .. } => true, // definitely a plugin
    }
}
<commit_msg>Rollup merge of #80203 - pierwill:pierwill-rustcmiddle-lint, r=oli-obk<commit_after>use std::cmp;

use crate::ich::StableHashingContext;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{builtin, Level, Lint, LintId};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
pub enum LintSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),

    /// Lint level was set by a command-line flag.
    /// The provided `Level` is the level specified on the command line.
    /// (The actual level may be lower due to `--cap-lints`.)
    CommandLine(Symbol, Level),
}

impl LintSource {
    pub fn name(&self) -> Symbol {
        match *self {
            LintSource::Default => symbol::kw::Default,
            LintSource::Node(name, _, _) => name,
            LintSource::CommandLine(name, _) => name,
        }
    }

    pub fn span(&self) -> Span {
        match *self {
            LintSource::Default => DUMMY_SP,
            LintSource::Node(_, span, _) => span,
            LintSource::CommandLine(_, _) => DUMMY_SP,
        }
    }
}

pub type LevelSource = (Level, LintSource);

pub struct LintLevelSets {
    pub list: Vec<LintSet>,
    pub lint_cap: Level,
}

pub enum LintSet {
    CommandLine {
        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
        // flag.
        specs: FxHashMap<LintId, LevelSource>,
    },

    Node {
        specs: FxHashMap<LintId, LevelSource>,
        parent: u32,
    },
}

impl LintLevelSets {
    pub fn new() -> Self {
        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
    }

    pub fn get_lint_level(
        &self,
        lint: &'static Lint,
        idx: u32,
        aux: Option<&FxHashMap<LintId, LevelSource>>,
        sess: &Session,
    ) -> LevelSource {
        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);

        // If `level` is none then we actually assume the default level for this
        // lint.
        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));

        // If we're about to issue a warning, check at the last minute for any
        // directives against the warnings "lint". If, for example, there's an
        // `allow(warnings)` in scope then we want to respect that instead.
        if level == Level::Warn {
            let (warnings_level, warnings_src) =
                self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
            if let Some(configured_warning_level) = warnings_level {
                if configured_warning_level != Level::Warn {
                    level = configured_warning_level;
                    src = warnings_src;
                }
            }
        }

        // Ensure that we never exceed the `--cap-lints` argument.
        level = cmp::min(level, self.lint_cap);

        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
            // Ensure that we never exceed driver level.
            level = cmp::min(*driver_level, level);
        }

        (level, src)
    }

    pub fn get_lint_id_level(
        &self,
        id: LintId,
        mut idx: u32,
        aux: Option<&FxHashMap<LintId, LevelSource>>,
    ) -> (Option<Level>, LintSource) {
        if let Some(specs) = aux {
            if let Some(&(level, src)) = specs.get(&id) {
                return (Some(level), src);
            }
        }
        loop {
            match self.list[idx as usize] {
                LintSet::CommandLine { ref specs } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    return (None, LintSource::Default);
                }
                LintSet::Node { ref specs, parent } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    idx = parent;
                }
            }
        }
    }
}

pub struct LintLevelMap {
    pub sets: LintLevelSets,
    pub id_to_set: FxHashMap<HirId, u32>,
}

impl LintLevelMap {
    /// If the `id` was previously registered with `register_id` when building
    /// this `LintLevelMap` this returns the corresponding lint level and source
    /// of the lint level for the lint provided.
    ///
    /// If the `id` was not previously registered, returns `None`. If `None` is
    /// returned then the parent of `id` should be acquired and this function
    /// should be called again.
    pub fn level_and_source(
        &self,
        lint: &'static Lint,
        id: HirId,
        session: &Session,
    ) -> Option<LevelSource> {
        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let LintLevelMap { ref sets, ref id_to_set } = *self;

        id_to_set.hash_stable(hcx, hasher);

        let LintLevelSets { ref list, lint_cap } = *sets;

        lint_cap.hash_stable(hcx, hasher);

        hcx.while_hashing_spans(true, |hcx| {
            list.len().hash_stable(hcx, hasher);

            // We are working under the assumption here that the list of
            // lint-sets is built in a deterministic order.
            for lint_set in list {
                ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);

                match *lint_set {
                    LintSet::CommandLine { ref specs } => {
                        specs.hash_stable(hcx, hasher);
                    }
                    LintSet::Node { ref specs, parent } => {
                        specs.hash_stable(hcx, hasher);
                        parent.hash_stable(hcx, hasher);
                    }
                }
            }
        })
    }
}

pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>);

impl<'a> LintDiagnosticBuilder<'a> {
    /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
    pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
        self.0.set_primary_message(msg);
        self.0
    }

    /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
    pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> {
        LintDiagnosticBuilder(err)
    }
}

pub fn struct_lint_level<'s, 'd>(
    sess: &'s Session,
    lint: &'static Lint,
    level: Level,
    src: LintSource,
    span: Option<MultiSpan>,
    decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
) {
    // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
    // the "real" work.
    fn struct_lint_level_impl(
        sess: &'s Session,
        lint: &'static Lint,
        level: Level,
        src: LintSource,
        span: Option<MultiSpan>,
        decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
    ) {
        // Check for future incompatibility lints and issue a stronger warning.
        let lint_id = LintId::of(lint);
        let future_incompatible = lint.future_incompatible;

        let has_future_breakage =
            future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());

        let mut err = match (level, span) {
            (Level::Allow, span) => {
                if has_future_breakage {
                    if let Some(span) = span {
                        sess.struct_span_allow(span, "")
                    } else {
                        sess.struct_allow("")
                    }
                } else {
                    return;
                }
            }
            (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
            (Level::Warn, None) => sess.struct_warn(""),
            (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
            (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
        };

        // If this code originates in a foreign macro, aka something that this crate
        // did not itself author, then it's likely that there's nothing this crate
        // can do about it. We probably want to skip the lint entirely.
        if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
            // Any suggestions made here are likely to be incorrect, so anything we
            // emit shouldn't be automatically fixed by rustfix.
            err.allow_suggestions(false);

            // If this is a future incompatible lint it'll become a hard error, so
            // we have to emit *something*. Also, if this lint occurs in the
            // expansion of a macro from an external crate, allow individual lints
            // to opt-out from being reported.
            if future_incompatible.is_none() && !lint.report_in_external_macro {
                err.cancel();
                // Don't continue further, since we don't want to have
                // `diag_span_note_once` called for a diagnostic that isn't emitted.
                return;
            }
        }

        let name = lint.name_lower();
        match src {
            LintSource::Default => {
                sess.diag_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    &format!("`#[{}({})]` on by default", level.as_str(), name),
                );
            }
            LintSource::CommandLine(lint_flag_val, orig_level) => {
                let flag = match orig_level {
                    Level::Warn => "-W",
                    Level::Deny => "-D",
                    Level::Forbid => "-F",
                    Level::Allow => "-A",
                };
                let hyphen_case_lint_name = name.replace("_", "-");
                if lint_flag_val.as_str() == name {
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "requested on the command line with `{} {}`",
                            flag, hyphen_case_lint_name
                        ),
                    );
                } else {
                    let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`{} {}` implied by `{} {}`",
                            flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
                        ),
                    );
                }
            }
            LintSource::Node(lint_attr_name, src, reason) => {
                if let Some(rationale) = reason {
                    err.note(&rationale.as_str());
                }
                sess.diag_span_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    src,
                    "the lint level is defined here",
                );
                if lint_attr_name.as_str() != name {
                    let level_str = level.as_str();
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`#[{}({})]` implied by `#[{}({})]`",
                            level_str, name, level_str, lint_attr_name
                        ),
                    );
                }
            }
        }

        err.code(DiagnosticId::Lint { name, has_future_breakage });

        if let Some(future_incompatible) = future_incompatible {
            const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
                 it will become a hard error";

            let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
                "once this method is added to the standard library, \
                 the ambiguity may cause an error or change in behavior!"
                    .to_owned()
            } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
                "this borrowing pattern was not meant to be accepted, \
                 and may become a hard error in the future"
                    .to_owned()
            } else if let Some(edition) = future_incompatible.edition {
                format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
            } else {
                format!("{} in a future release!", STANDARD_MESSAGE)
            };
            let citation = format!("for more information, see {}", future_incompatible.reference);
            err.warn(&explanation);
            err.note(&citation);
        }

        // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
        decorate(LintDiagnosticBuilder::new(err));
    }
    struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
}

/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
    let expn_data = span.ctxt().outer_expn_data();
    match expn_data.kind {
        ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => {
            false
        }
        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
        ExpnKind::Macro(MacroKind::Bang, _) => {
            // Dummy span for the `def_site` means it's an external macro.
            expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
        }
        ExpnKind::Macro { .. } => true, // definitely a plugin
    }
}
<|endoftext|>


<commit_before>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![crate_name = "snowmew-render-mux"]
#![license = "ASL2"]
#![crate_type = "lib"]
#![comment = "A game engine in rust"]
#![allow(dead_code)]

extern crate sync;

extern crate opencl;
extern crate "snowmew-render-gfx" as gfx;
extern crate "snowmew-core" as snowmew;
extern crate "snowmew-render" as azdo;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render-data" as render_data;

use std::os;

use opencl::hl::Device;
use sync::Arc;

use snowmew::common::ObjectKey;
use snowmew::io::Window;

use render_data::RenderData;

impl<'r, RD: RenderData+Send> snowmew::Render<RD> for RenderMux<'r, RD> {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.render.update(db, scene, camera)
    }
}

pub struct RenderMux<'r, RD> {
    render: Box<snowmew::Render<RD> + 'r>
}

impl<'r, RD: RenderData+Send> snowmew::RenderFactory<RD, RenderMux<'r, RD>> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<Device>>) -> RenderMux<RD> {

        let s = match os::getenv("GFX") {
            Some(s) => s,
            None => "false".to_string()
        };
        let s: String = s.as_slice().chars().map(|c| c.to_lowercase()).collect();

        let use_gfx = match s.as_slice() {
            "true" => Some(true),
            "enabled" => Some(true),
            "1" => Some(true),
            "false" => Some(false),
            "disabled" => Some(false),
            "0" => Some(false),
            _ => None
        };

        let rm: RenderMux<RD> = if use_gfx.is_some() && use_gfx.unwrap() {
            let rf: Box<snowmew::RenderFactory<RD, gfx::RenderManager<RD>>> = box gfx::RenderFactory::new();
            let render: Box<gfx::RenderManager<RD>> = box rf.init(io, window, size, cl);
            RenderMux {
                render: render as Box<snowmew::Render<RD>>
            }
        } else {
            let rf: Box<snowmew::RenderFactory<RD, azdo::RenderManager>> = box azdo::RenderFactory::new();
            let render: Box<azdo::RenderManager> = box rf.init(io, window, size, cl);
            RenderMux {
                render: render as Box<snowmew::Render<RD>>
            }
        };
        rm
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<commit_msg>Use GFX as defualt render<commit_after>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![crate_name = "snowmew-render-mux"]
#![license = "ASL2"]
#![crate_type = "lib"]
#![comment = "A game engine in rust"]
#![allow(dead_code)]

extern crate sync;

extern crate opencl;
extern crate "snowmew-render-gfx" as gfx;
extern crate "snowmew-core" as snowmew;
extern crate "snowmew-render" as azdo;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render-data" as render_data;

use std::os;

use opencl::hl::Device;
use sync::Arc;

use snowmew::common::ObjectKey;
use snowmew::io::Window;

use render_data::RenderData;

impl<'r, RD: RenderData+Send> snowmew::Render<RD> for RenderMux<'r, RD> {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.render.update(db, scene, camera)
    }
}

pub struct RenderMux<'r, RD> {
    render: Box<snowmew::Render<RD> + 'r>
}

impl<'r, RD: RenderData+Send> snowmew::RenderFactory<RD, RenderMux<'r, RD>> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<Device>>) -> RenderMux<RD> {

        let s = match os::getenv("AZDO") {
            Some(s) => s,
            None => "false".to_string()
        };
        let s: String = s.as_slice().chars().map(|c| c.to_lowercase()).collect();

        let use_azdo = match s.as_slice() {
            "true" => Some(true),
            "enabled" => Some(true),
            "1" => Some(true),
            "false" => Some(false),
            "disabled" => Some(false),
            "0" => Some(false),
            _ => None
        };

        let rm: RenderMux<RD> = if use_azdo.is_some() && use_azdo.unwrap() {
            let rf: Box<snowmew::RenderFactory<RD, azdo::RenderManager>> = box azdo::RenderFactory::new();
            let render: Box<azdo::RenderManager> = box rf.init(io, window, size, cl);
            RenderMux {
                render: render as Box<snowmew::Render<RD>>
            }
        } else {
            let rf: Box<snowmew::RenderFactory<RD, gfx::RenderManager<RD>>> = box gfx::RenderFactory::new();
            let render: Box<gfx::RenderManager<RD>> = box rf.init(io, window, size, cl);
            RenderMux {
                render: render as Box<snowmew::Render<RD>>
            }
        };
        rm
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<|endoftext|>