<commit_before>extern crate postgres;
extern crate chrono;
extern crate regex;
extern crate hyper;
extern crate hyper_native_tls;

use std::env;
use std::str;
use std::io::Read;

use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

use postgres::{Connection, TlsMode};
use chrono::{DateTime, Utc};
use regex::Regex;

struct DonationEntry {
    id: i32,
    timestamp: DateTime<Utc>,
    donation_count: i32,
    donation_total: i32,
    event_id: String,
}

fn main() {
	let database_uri: String = env::var("GDQ_DATABASE_URI").unwrap();
    let live_id: String =       env::var("GDQ_LIVE_EVENT_ID").unwrap();

    let conn = Connection::connect(database_uri.as_str(), TlsMode::None).unwrap();
    /*conn.execute("DROP TABLE DonationEntry", &[]).unwrap();
    conn.execute("CREATE TABLE DonationEntry (
                    id              SERIAL PRIMARY KEY,
                    timestamp       TIMESTAMP WITH TIME ZONE NOT NULL,
                    donation_count           INT,
                    donation_total           INT
                  )", &[]).unwrap();
    */

    let (count, total) = get_current_donation_stats();

    let new_entry = DonationEntry {
    	id: 0,
        timestamp: Utc::now(),
        donation_count: count,
        donation_total: total,
        event_id: live_id,
    };
    conn.execute("INSERT INTO DonationEntry (timestamp, donation_count, donation_total, event_id) VALUES ($1, $2, $3, $4)",
                 &[&new_entry.timestamp, &new_entry.donation_count, &new_entry.donation_total, &new_entry.event_id]).unwrap();

    let result = conn.query("SELECT id, timestamp, donation_count, donation_total, event_id FROM DonationEntry ORDER BY timestamp DESC LIMIT 1", &[]).unwrap();
    assert_eq!(result.len(), 1);
    for row in &result {
        let entry = DonationEntry {
            id: row.get(0),
            timestamp: row.get(1),
            donation_count: row.get(2),
            donation_total: row.get(3),
            event_id: row.get(4),
        };
        println!("Successfuly added row: id: {}, timestamp: {}, count: {}, total: {}, event_id:{}", entry.id, entry.timestamp, entry.donation_count, entry.donation_total, entry.event_id);
    }
}

fn get_current_donation_stats() -> (i32, i32) {

    //send the request and read the response
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let scrape_url: String = env::var("GDQ_SCRAPE_URL").unwrap();
    //let scrape_url = "https://gamesdonequick.com/tracker/19";

    let mut response = client.get(scrape_url.as_str()).send().unwrap();

    assert_eq!(response.status, hyper::Ok);

    let mut response_string = String::new();
    response.read_to_string(&mut response_string).unwrap();

    //pull out the donation total and donation count text
    let parse_regex = Regex::new(r"Donation Total:\s*\$(?P<total>[\d,]+)(?:[.\d]+)?\s*\((?P<count>\d+)\)\s*\—").unwrap();
    let captures = parse_regex.captures(&response_string).unwrap();

    let matched_total = captures.name("total").unwrap().as_str();
    let matched_count = captures.name("count").unwrap().as_str();

    //remove any comma separators before parsing
    let parsed_total = matched_total.replace(",", "").parse::<i32>().unwrap();
    let parsed_count = matched_count.replace(",", "").parse::<i32>().unwrap();

	(parsed_count, parsed_total)
}<commit_msg>Don't duplicate event id information<commit_after>extern crate postgres;
extern crate chrono;
extern crate regex;
extern crate hyper;
extern crate hyper_native_tls;

use std::env;
use std::str;
use std::io::Read;

use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

use postgres::{Connection, TlsMode};
use chrono::{DateTime, Utc};
use regex::Regex;

struct DonationEntry {
    id: i32,
    timestamp: DateTime<Utc>,
    donation_count: i32,
    donation_total: i32,
    event_id: String,
}

fn main() {
	let database_uri: String = env::var("GDQ_DATABASE_URI").unwrap();
    let live_id: String =       env::var("GDQ_LIVE_EVENT_ID").unwrap();

    let conn = Connection::connect(database_uri.as_str(), TlsMode::None).unwrap();
    /*conn.execute("DROP TABLE DonationEntry", &[]).unwrap();
    conn.execute("CREATE TABLE DonationEntry (
                    id              SERIAL PRIMARY KEY,
                    timestamp       TIMESTAMP WITH TIME ZONE NOT NULL,
                    donation_count           INT,
                    donation_total           INT
                  )", &[]).unwrap();
    */

    let (count, total) = get_current_donation_stats(&live_id);

    let new_entry = DonationEntry {
    	id: 0,
        timestamp: Utc::now(),
        donation_count: count,
        donation_total: total,
        event_id: live_id,
    };
    conn.execute("INSERT INTO DonationEntry (timestamp, donation_count, donation_total, event_id) VALUES ($1, $2, $3, $4)",
                 &[&new_entry.timestamp, &new_entry.donation_count, &new_entry.donation_total, &new_entry.event_id]).unwrap();

    let result = conn.query("SELECT id, timestamp, donation_count, donation_total, event_id FROM DonationEntry ORDER BY timestamp DESC LIMIT 1", &[]).unwrap();
    assert_eq!(result.len(), 1);
    for row in &result {
        let entry = DonationEntry {
            id: row.get(0),
            timestamp: row.get(1),
            donation_count: row.get(2),
            donation_total: row.get(3),
            event_id: row.get(4),
        };
        println!("Successfuly added row: id: {}, timestamp: {}, count: {}, total: {}, event_id:{}", entry.id, entry.timestamp, entry.donation_count, entry.donation_total, entry.event_id);
    }
}

fn get_current_donation_stats(event_id: &str) -> (i32, i32) {

    //send the request and read the response
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let scrape_url = format!("https://gamesdonequick.com/tracker/index/{}", event_id);

    let mut response = client.get(scrape_url.as_str()).send().unwrap();

    assert_eq!(response.status, hyper::Ok);

    let mut response_string = String::new();
    response.read_to_string(&mut response_string).unwrap();

    //pull out the donation total and donation count text
    let parse_regex = Regex::new(r"Donation Total:\s*\$(?P<total>[\d,]+)(?:[.\d]+)?\s*\((?P<count>\d+)\)\s*\—").unwrap();
    let captures = parse_regex.captures(&response_string).unwrap();

    let matched_total = captures.name("total").unwrap().as_str();
    let matched_count = captures.name("count").unwrap().as_str();

    //remove any comma separators before parsing
    let parsed_total = matched_total.replace(",", "").parse::<i32>().unwrap();
    let parsed_count = matched_count.replace(",", "").parse::<i32>().unwrap();

	(parsed_count, parsed_total)
}<|endoftext|>


<commit_before>//! Converts Qt docs from the internal format.

use log::{info, trace};
use ritual_common::errors::{bail, err_msg, Result, ResultExt};
use rusqlite;
use select::document::Document;
use std::path::Path;

/// Decoded documentation data.
#[derive(Debug)]
pub struct DocData {
    index: Vec<DocIndexItem>,
    connection: rusqlite::Connection,
}

/// An item of the documentation's index.
#[derive(Debug, Clone)]
pub struct DocIndexItem {
    /// Identifier in the index.
    /// For types and methods, this is roughly the same as
    /// the fully qualified name but has some quirks.
    pub name: String,
    /// Identifier of the virtual HTML file this item refers to.
    pub document_id: i32,
    /// HTML link anchor in the file this item refers to,
    /// or `None` if the item refers to the entire file (e.g. if it's a class).
    pub anchor: Option<String>,
    /// If `true`, this item was previously accessed using `DocData::find_index_item`.
    pub accessed: bool,
}

use std::io::Read;

use compress;

impl DocData {
    /// Returns all index items.
    pub fn index(&self) -> &[DocIndexItem] {
        &self.index
    }

    /// Returns parsed HTML document by id.
    pub fn document(&self, id: i32) -> Result<Document> {
        let file_data_query = "select Data from FileDataTable where Id==?";
        let mut file_data_query = self.connection.prepare(file_data_query)?;
        let mut file_data = file_data_query.query(&[&id])?;
        let file_data = file_data.next().ok_or_else(|| err_msg("invalid file id"))?;
        let file_data = file_data?;
        let file_data: Vec<u8> = file_data.get_checked(0)?;
        let mut file_html = Vec::new();
        compress::zlib::Decoder::new(&file_data[4..])
            .read_to_end(&mut file_html)
            .with_context(|_| "zlib decoder failed")?;
        let file_html = String::from_utf8_lossy(&file_html);
        Ok(Document::from(file_html.as_ref()))
    }

    /// Returns virtual file name of the document by id.
    pub fn file_name(&self, id: i32) -> Result<String> {
        let query = "select Name from FileNameTable where FileId==?";
        let mut query = self.connection.prepare(query)?;
        let mut result = query.query(&[&id])?;
        let row = result.next().ok_or_else(|| err_msg("invalid file id"))?;
        let row = row?;
        Ok(row.get_checked(0)?)
    }

    /// Searches for an index item by lambda condition.
    pub fn find_index_item(
        &mut self,
        mut f: impl FnMut(&DocIndexItem) -> bool,
    ) -> Option<DocIndexItem> {
        self.index.iter_mut().find(|item| f(item)).and_then(|item| {
            item.accessed = true;
            Some(item.clone())
        })
    }

    /// Parses Qt documentation of module `qt_crate_name` located at `docs_path`.
    pub fn new(qt_crate_name: &str, docs_path: &Path) -> Result<Self> {
        if !docs_path.exists() {
            bail!(
                "Documentation directory does not exist: {}",
                docs_path.display()
            );
        }
        let doc_file_name = if qt_crate_name.starts_with("3d_") {
            "3d".to_string()
        } else {
            qt_crate_name.replace("_", "")
        };

        let doc_file_path = docs_path.join(format!("{}.qch", doc_file_name));
        if !doc_file_path.exists() {
            bail!(
                "Documentation file does not exist: {}",
                doc_file_path.display()
            );
        }
        info!("Adding Qt documentation from {}", doc_file_path.display());
        let connection = rusqlite::Connection::open_with_flags(
            &doc_file_path,
            rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY,
        )?;

        let mut index_data = Vec::new();
        {
            let index_query = "select IndexTable.Identifier, IndexTable.FileId, IndexTable.Anchor \
                               from IndexTable";
            let mut index = connection.prepare(index_query)?;
            let mut index_rows = index.query(rusqlite::NO_PARAMS)?;
            while let Some(index_row) = index_rows.next() {
                let index_row = index_row?;
                let name: String = index_row.get_checked(0)?;
                let file_id: i32 = index_row.get_checked(1)?;
                let anchor: Option<String> = index_row.get_checked(2)?;
                index_data.push(DocIndexItem {
                    name,
                    document_id: file_id,
                    anchor,
                    accessed: false,
                });
            }
        }
        trace!("doc index: {:?}", index_data);
        Ok(DocData {
            index: index_data,
            connection,
        })
    }
}
<commit_msg>fix qt3d docs file search<commit_after>//! Converts Qt docs from the internal format.

use log::{info, trace};
use ritual_common::errors::{bail, err_msg, Result, ResultExt};
use rusqlite;
use select::document::Document;
use std::path::Path;

/// Decoded documentation data.
#[derive(Debug)]
pub struct DocData {
    index: Vec<DocIndexItem>,
    connection: rusqlite::Connection,
}

/// An item of the documentation's index.
#[derive(Debug, Clone)]
pub struct DocIndexItem {
    /// Identifier in the index.
    /// For types and methods, this is roughly the same as
    /// the fully qualified name but has some quirks.
    pub name: String,
    /// Identifier of the virtual HTML file this item refers to.
    pub document_id: i32,
    /// HTML link anchor in the file this item refers to,
    /// or `None` if the item refers to the entire file (e.g. if it's a class).
    pub anchor: Option<String>,
    /// If `true`, this item was previously accessed using `DocData::find_index_item`.
    pub accessed: bool,
}

use std::io::Read;

use compress;

impl DocData {
    /// Returns all index items.
    pub fn index(&self) -> &[DocIndexItem] {
        &self.index
    }

    /// Returns parsed HTML document by id.
    pub fn document(&self, id: i32) -> Result<Document> {
        let file_data_query = "select Data from FileDataTable where Id==?";
        let mut file_data_query = self.connection.prepare(file_data_query)?;
        let mut file_data = file_data_query.query(&[&id])?;
        let file_data = file_data.next().ok_or_else(|| err_msg("invalid file id"))?;
        let file_data = file_data?;
        let file_data: Vec<u8> = file_data.get_checked(0)?;
        let mut file_html = Vec::new();
        compress::zlib::Decoder::new(&file_data[4..])
            .read_to_end(&mut file_html)
            .with_context(|_| "zlib decoder failed")?;
        let file_html = String::from_utf8_lossy(&file_html);
        Ok(Document::from(file_html.as_ref()))
    }

    /// Returns virtual file name of the document by id.
    pub fn file_name(&self, id: i32) -> Result<String> {
        let query = "select Name from FileNameTable where FileId==?";
        let mut query = self.connection.prepare(query)?;
        let mut result = query.query(&[&id])?;
        let row = result.next().ok_or_else(|| err_msg("invalid file id"))?;
        let row = row?;
        Ok(row.get_checked(0)?)
    }

    /// Searches for an index item by lambda condition.
    pub fn find_index_item(
        &mut self,
        mut f: impl FnMut(&DocIndexItem) -> bool,
    ) -> Option<DocIndexItem> {
        self.index.iter_mut().find(|item| f(item)).and_then(|item| {
            item.accessed = true;
            Some(item.clone())
        })
    }

    /// Parses Qt documentation of module `qt_crate_name` located at `docs_path`.
    pub fn new(qt_crate_name: &str, docs_path: &Path) -> Result<Self> {
        if !docs_path.exists() {
            bail!(
                "Documentation directory does not exist: {}",
                docs_path.display()
            );
        }
        let doc_file_name = if qt_crate_name.starts_with("qt_3d_") {
            "qt3d".to_string()
        } else {
            qt_crate_name.replace("_", "")
        };

        let doc_file_path = docs_path.join(format!("{}.qch", doc_file_name));
        if !doc_file_path.exists() {
            bail!(
                "Documentation file does not exist: {}",
                doc_file_path.display()
            );
        }
        info!("Adding Qt documentation from {}", doc_file_path.display());
        let connection = rusqlite::Connection::open_with_flags(
            &doc_file_path,
            rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY,
        )?;

        let mut index_data = Vec::new();
        {
            let index_query = "select IndexTable.Identifier, IndexTable.FileId, IndexTable.Anchor \
                               from IndexTable";
            let mut index = connection.prepare(index_query)?;
            let mut index_rows = index.query(rusqlite::NO_PARAMS)?;
            while let Some(index_row) = index_rows.next() {
                let index_row = index_row?;
                let name: String = index_row.get_checked(0)?;
                let file_id: i32 = index_row.get_checked(1)?;
                let anchor: Option<String> = index_row.get_checked(2)?;
                index_data.push(DocIndexItem {
                    name,
                    document_id: file_id,
                    anchor,
                    accessed: false,
                });
            }
        }
        trace!("doc index: {:?}", index_data);
        Ok(DocData {
            index: index_data,
            connection,
        })
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Minus,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 60,
    Add = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    Neg(Box<Exp>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) |
            Exp::Undefined | Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "}}")
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "return "));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>add equality/inequality binary expressions<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,
    Le,
    Lt,
    Minus,
    Neq,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
            BinOp::Neq => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    Neg(Box<Exp>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) |
            Exp::Undefined | Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "}}")
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "return "));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<|endoftext|>


<commit_before>use token::{Token, Type};

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Ast {
    pub node_val: Option<Token>,
    child_nodes: Vec<Ast>
}

pub trait AstTrait {
    fn push_child(&mut self, ast: Ast);
    fn pop_child(&mut self) -> Option<Ast>;
    fn get_child(&mut self, index: usize) -> Option<Ast>;
    fn insert_child(&mut self, child: Ast, index: usize) -> bool;
    fn child_count(&self) -> usize;
    fn dump_children(&mut self) -> Vec<Ast>;
    fn clone_children(&self) -> Vec<Ast>;
}

impl AstTrait for Ast {
    fn push_child(&mut self, ast: Ast) {
        self.child_nodes.push(ast);
    }

    fn pop_child(&mut self) -> Option<Ast> {
        self.child_nodes.pop()
    }

    fn get_child(&mut self, index: usize) -> Option<Ast> {
        match self.child_nodes.len() > index {
            true => Some(self.child_nodes.remove(index)),
            false => None
        }
    }

    fn insert_child(&mut self, child: Ast, index: usize) -> bool {
        if self.child_nodes.len() >= index {
            self.child_nodes.insert(index, child);
            true
        } else {
            false
        }
    }

    fn child_count(&self) -> usize {
        self.child_nodes.len()
    }

    fn dump_children(&mut self) -> Vec<Ast> {
        let children = self.child_nodes.clone();
        self.child_nodes.clear();
        children
    }

    fn clone_children(&self) -> Vec<Ast> {
        self.child_nodes.clone()
    }
}

impl Ast {
    pub fn new(node: Token) -> Self {
        Ast {
            node_val: Some(node),
            child_nodes: Vec::new()
        }
    }

    pub fn new_null() -> Self {
        Ast {
            node_val: None,
            child_nodes: Vec::new()
        }
    }

    pub fn is_function(&mut self) -> bool {
        match self.get_child(0) {
            Some(child) => {
                let result = match child.node_val {
                    Some(ref tok) => {
                        match tok.tok_type {
                            Type::Func => true,
                            _ => false
                        }
                    },
                    None => false
                };
                self.insert_child(child, 0);
                result
            },
            None => false
        }
    }
}

// impl PartialEq for Ast {
//
// }
<commit_msg>update<commit_after>use token::{Token, Type};

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Ast {
    pub node_val: Option<Token>,
    child_nodes: Vec<Ast>
}

pub trait AstTrait {
    fn push_child(&mut self, ast: Ast);
    fn pop_child(&mut self) -> Option<Ast>;
    fn get_child(&mut self, index: usize) -> Option<Ast>;
    fn insert_child(&mut self, child: Ast, index: usize) -> bool;
    fn child_count(&self) -> usize;
    fn dump_children(&mut self) -> Vec<Ast>;
    fn clone_children(&self) -> Vec<Ast>;
}

impl AstTrait for Ast {
    fn push_child(&mut self, ast: Ast) {
        self.child_nodes.push(ast);
    }

    fn pop_child(&mut self) -> Option<Ast> {
        self.child_nodes.pop()
    }

    fn get_child(&mut self, index: usize) -> Option<Ast> {
        match self.child_nodes.len() > index {
            true => Some(self.child_nodes.remove(index)),
            false => None
        }
    }

    fn insert_child(&mut self, child: Ast, index: usize) -> bool {
        if self.child_nodes.len() >= index {
            self.child_nodes.insert(index, child);
            true
        } else {
            false
        }
    }

    fn child_count(&self) -> usize {
        self.child_nodes.len()
    }

    fn dump_children(&mut self) -> Vec<Ast> {
        let children = self.child_nodes.clone();
        self.child_nodes.clear();
        children
    }

    fn clone_children(&self) -> Vec<Ast> {
        self.child_nodes.clone()
    }
}

impl Ast {
    pub fn new(node: Token) -> Self {
        Ast {
            node_val: Some(node),
            child_nodes: Vec::new()
        }
    }

    pub fn new_null() -> Self {
        Ast {
            node_val: None,
            child_nodes: Vec::new()
        }
    }

    pub fn is_function(&mut self) -> bool {
        match self.get_child(0) {
            Some(child) => {
                let result = match child.node_val {
                    Some(ref tok) => {
                        match tok.tok_type {
                            Type::Func => true,
                            _ => false
                        }
                    },
                    None => false
                };
                self.insert_child(child, 0);
                result
            },
            None => false
        }
    }
}
<|endoftext|>


<commit_before>use std::string;
use std::vec;
use std::result;

pub enum Ast{
    Token(string::String),
    SubList(vec::Vec<Ast>),
}

impl Ast{
    pub fn from_string(s: string::String) -> result::Result<Ast, &'static str> {
        //First add spaces to ensure brackets end up as tokens by themselves
        let mut s = s.replace("(", " ( ");
        s = s.replace(")", " ) ");
        let str = s.trim();
        let mut v: vec::Vec<string::String> = str.split(" ").map(|s| s.to_string()).collect();

        v.reverse();
        match v.pop() {
            None => return Err("Needs some tokens..."),
            Some(str) => match &str[..]{
                "(" => (),
                _ => {
                    return Err("First token must be \"(\".")},
            },
        };
        match Ast::from_string_vec(v){
            Ok((_, ast)) => Ok(ast),
            Err(e) => Err(e),
        }
    }

    fn from_string_vec(mut v : vec::Vec<string::String>) -> result::Result<(vec::Vec<string::String>, Ast), &'static str> {
        let mut ast_vec = vec![];
        loop{
            match v.pop() {
                None => break,
                Some(str) => match &str[..] {
                    ")" => return Ok((v, Ast::SubList(ast_vec))),
                    "(" => {
                        match Ast::from_string_vec(v.clone()) {
                            Ok((v_ret, ast)) => {
                                ast_vec.push(ast);
                                v = v_ret;
                            },
                            Err(s) => return Err(s),
                        }
                    },
                    "" => (),
                    " " => (),
                    _ => {
                        //println!("Debug: {}", str);
                        ast_vec.push(Ast::Token(str.to_string()))
                    },
                }
            };
        };

        Err("Seem to have insufficient closing brackets to parse ast!")
    }

    pub fn to_string(self: Ast) -> string::String {
        self.to_string_with_indent(0)
    }

    fn to_string_with_indent(self: Ast, indent: i32) -> string::String {
        let mut output = "".to_string();

        match self {
            Ast::Token(t) => output.push_str(&t[..]),
            Ast::SubList(v) => {
                output.push_str("\n");
                for _ in 0..indent{
                    output.push_str(" ");
                }
                output.push_str("(");
                for element in v {
                    output.push_str(&element.to_string_with_indent(indent+1)[..]);
                }
                output.pop(); //don't want the ugly extra whitespace
                output.push_str(")");
            },
        };

        output.push_str(" ");
        return output;
    }
}
<commit_msg>Minor changes<commit_after>use std::string;
use std::vec;
use std::result;

pub enum Ast{
    Token(string::String),
    SubList(vec::Vec<Ast>),
}

impl Ast{
    pub fn from_string(s: string::String) -> result::Result<Ast, &'static str> {
        //First add spaces to ensure brackets end up as tokens by themselves
        let mut s = s.replace("(", " ( ");
        s = s.replace(")", " ) ");
        let str = s.trim();
        let mut v: vec::Vec<string::String> = str.split(" ").map(|s| s.to_string()).collect();

        v.reverse();

        match v.pop() {
            None => return Err("Needs some tokens..."),
            Some(str) => match &str[..]{
                "(" => (),
                _ => {
                    return Err("First token must be \"(\".")},
            },
        };

        match Ast::from_string_vec(v){
            Ok((_, ast)) => Ok(ast),
            Err(e) => Err(e),
        }
    }

    fn from_string_vec(mut v : vec::Vec<string::String>) -> result::Result<(vec::Vec<string::String>, Ast), &'static str> {
        let mut ast_vec = vec![];

        loop{
            match v.pop() {
                None => break,
                Some(str) => match &str[..] {
                    ")" => return Ok((v, Ast::SubList(ast_vec))),
                    "(" => {
                        match Ast::from_string_vec(v.clone()) {
                            Ok((v_ret, ast)) => {
                                ast_vec.push(ast);
                                v = v_ret;
                            },
                            Err(s) => return Err(s),
                        }
                    },
                    "" => (),
                    " " => (),
                    _ => {
                        //println!("Debug: {}", str);
                        ast_vec.push(Ast::Token(str.to_string()))
                    },
                }
            };
        };

        Err("Seem to have insufficient closing brackets to parse ast!")
    }

    pub fn to_string(self: Ast) -> string::String {
        self.to_string_with_indent(0)
    }

    fn to_string_with_indent(self: Ast, indent: i32) -> string::String {
        let mut output = "".to_string();

        match self {
            Ast::Token(t) => output.push_str(&t[..]),
            Ast::SubList(v) => {
                output.push_str("\n");
                for _ in 0..indent{
                    output.push_str(" ");
                }
                output.push_str("(");
                for element in v {
                    output.push_str(&element.to_string_with_indent(indent+1)[..]);
                }
                output.pop(); //don't want the ugly extra whitespace
                output.push_str(")");
            },
        };

        output.push_str(" ");
        return output;
    }
}
<|endoftext|>


<commit_before>
/*
 * Interpreter for Basic C like language
 * AST(Abstract Syntax Tree) Module
 */

use lexer::*;
/*
#[derive(Debug)]
pub struct Program {
    pub stmts: Vec<Expr>
}

#[derive(Debug)]
pub struct Expr {
    pub span: Span,
    pub node: Expr_
}

#[derive(Debug)]
pub enum Expr_ {
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Var(String),
    Assign(String, Box<Expr>),
    Print(Box<Expr>),
    Literal(i64),
}*/

pub enum Node {
    OperatorNode {leftNode: Option<Box<Node>>, rightNode: Option<Box<Node>>},
    NumberNode {value: i64},
    VariableNode {value: String},
    StringNode {value: String}
}
<commit_msg>Updated AST<commit_after>
/*
 * Interpreter for Basic C like language
 * AST(Abstract Syntax Tree) Module
 */

use lexer::*;

#[derive(Debug)]
pub struct Expr {
    pub span: Span,
    pub node: Expr_
}

#[derive(Debug)]
pub enum Expr_ {
    // Add two expressions.
    Add(Box<Expr>, Box<Expr>),
    // Subtract two expressions
    Sub(Box<Expr>, Box<Expr>),
    // Multiply two expressions
    Mul(Box<Expr>, Box<Expr>),
    // Divide two expressions
    Div(Box<Expr>, Box<Expr>),
    // Variable expression
    Var(String),
    // Assignment expression
    Assign(String, Box<Expr>),
    // If expression 'if expr { expr } else { expr }'
    If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
    // Print expression
    Print(Box<Expr>),
    // Literal expression
    Literal(i64)
}

pub enum Node {
    OperatorNode {Children: Option<Vec<Node>>},
    NumberNode {value: i64},
    VariableNode {value: String},
    StringNode {value: String}
}
<|endoftext|>


<commit_before>extern crate collections;

use collections::dlist::DList;
use collections::Deque;

static CHB_MIN_SIZE:uint = 32u;

fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.mut_slice(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

struct ChbDataHolder{
    size: uint,
    data: Vec<u8>
}

struct ChbNode {
    dh: Box<ChbDataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

struct ChbChain {
    head: DList<Box<ChbNode>>,
    length: uint
}

fn chb_dh_new(size: uint) -> Box<ChbDataHolder> {
    let dh = box ChbDataHolder {
        size: size,
        data: Vec::from_elem(size, 0)
    };
    return dh;
}

// Impl + methods
fn chb_node_new(dh: Box<ChbDataHolder>) -> Box<ChbNode> {
    let n = box ChbNode {
        dh: dh,
        start: 0,
        end: 0
    };
    // ref dh ? auto, when using RC
    return n;
}

fn chb_node_size(node: &ChbNode) -> uint {
    node.end - node.start
}

fn chb_node_room(node: &ChbNode) -> uint {
    return node.dh.size - node.end;
}

fn chb_new() -> ChbChain {
    return ChbChain{
        head: DList::new(),
        length: 0
    }
}

fn chb_add_node_tail(chain: &mut ChbChain, node: Box<ChbNode>) {
    chain.length += chb_node_size(&*node);
    chain.head.push(node);
}

fn chb_add_node_head(chain: &mut ChbChain, node: Box<ChbNode>) {
    chain.length += chb_node_size(&*node);
    chain.head.push_front(node);
}

fn chb_create_node_tail(chain: &mut ChbChain, size: uint) {
    let nsize = if size < CHB_MIN_SIZE {
        size << 1
    } else {
        size
    };
    let node = chb_node_new(chb_dh_new(nsize)); // Box<ChbNode>
    chb_add_node_tail(chain, node);
}

fn chb_create_node_head(chain: &mut ChbChain, size: uint) {
    let nsize = if size < CHB_MIN_SIZE {
        size << 1
    } else {
        size
    };
    let mut node = chb_node_new(chb_dh_new(nsize)); // Box<ChbNode>
    let r = chb_node_room(&*node);
    node.start = r;
    node.end = r;
    chb_add_node_head(chain, node);
}

// XXX: maybe DEDUP append/prepend?
fn chb_append_bytes(dst: &mut ChbChain, data: &[u8]) {
    let size = data.len();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
    let should_create = match dst.head.back() {
        Some(nd) => {
            // Check is READONLY
            chb_node_room(&**nd) < size
        }
        None => {
            true
        }
    };
    if should_create {
        chb_create_node_tail(dst, size);
    }
    // node could not be None here
    let node = dst.head.back_mut().unwrap();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
    let end = node.end;
    blit(data.as_slice(), 0,
         node.dh.data.as_mut_slice(), end,
         size);
    node.end += size;
    dst.length += size;
}

fn chb_prepend_bytes(dst: &mut ChbChain, data: &[u8]) {
    let size = data.len();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
    let should_create = match dst.head.back() {
        Some(nd) => {
            // Check is READONLY
            size > nd.start
        }
        None => {
            true
        }
    };
    if should_create {
        chb_create_node_head(dst, size);
    }
    // node could not be None here
    let node = dst.head.back_mut().unwrap();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
    let start = node.start;
    blit(data.as_slice(), 0,
         node.dh.data.as_mut_slice(), start - size,
         size);
    node.start -= size;
    dst.length += size;
}

fn main() {
    let mut chain = chb_new();
    chb_append_bytes(&mut chain, "abcdefghijklmnop".as_bytes());
    chb_prepend_bytes(&mut chain, "xxx".as_bytes());
}
<commit_msg>[fix] prepend_bytes: .front()<commit_after>extern crate collections;

use collections::dlist::DList;
use collections::Deque;

static CHB_MIN_SIZE:uint = 32u;

fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.mut_slice(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

struct ChbDataHolder{
    size: uint,
    data: Vec<u8>
}

struct ChbNode {
    dh: Box<ChbDataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

struct ChbChain {
    head: DList<Box<ChbNode>>,
    length: uint
}

fn chb_dh_new(size: uint) -> Box<ChbDataHolder> {
    let dh = box ChbDataHolder {
        size: size,
        data: Vec::from_elem(size, 0)
    };
    return dh;
}

// Impl + methods
fn chb_node_new(dh: Box<ChbDataHolder>) -> Box<ChbNode> {
    let n = box ChbNode {
        dh: dh,
        start: 0,
        end: 0
    };
    // ref dh ? auto, when using RC
    return n;
}

fn chb_node_size(node: &ChbNode) -> uint {
    node.end - node.start
}

fn chb_node_room(node: &ChbNode) -> uint {
    return node.dh.size - node.end;
}

fn chb_new() -> ChbChain {
    return ChbChain{
        head: DList::new(),
        length: 0
    }
}

fn chb_add_node_tail(chain: &mut ChbChain, node: Box<ChbNode>) {
    chain.length += chb_node_size(&*node);
    chain.head.push(node);
}

fn chb_add_node_head(chain: &mut ChbChain, node: Box<ChbNode>) {
    chain.length += chb_node_size(&*node);
    chain.head.push_front(node);
}

// TODO: rename _back
fn chb_create_node_tail(chain: &mut ChbChain, size: uint) {
    let nsize = if size < CHB_MIN_SIZE {
        size << 1
    } else {
        size
    };
    let node = chb_node_new(chb_dh_new(nsize)); // Box<ChbNode>
    chb_add_node_tail(chain, node);
}

// TODO: rename _front
fn chb_create_node_head(chain: &mut ChbChain, size: uint) {
    let nsize = if size < CHB_MIN_SIZE {
        size << 1
    } else {
        size
    };
    let mut node = chb_node_new(chb_dh_new(nsize)); // Box<ChbNode>
    let r = chb_node_room(&*node);
    node.start = r;
    node.end = r;
    chb_add_node_head(chain, node);
}

// XXX: maybe DEDUP append/prepend?
// TODO: test: length, capacity, node size
fn chb_append_bytes(dst: &mut ChbChain, data: &[u8]) {
    let size = data.len();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
    let should_create = match dst.head.back() {
        Some(nd) => {
            // Check is READONLY
            chb_node_room(&**nd) < size
        }
        None => {
            true
        }
    };
    if should_create {
        chb_create_node_tail(dst, size);
    }
    // node could not be None here
    let node = dst.head.back_mut().unwrap();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
    let end = node.end;
    blit(data.as_slice(), 0,
         node.dh.data.as_mut_slice(), end,
         size);
    node.end += size;
    dst.length += size;
}

// TODO: test: length, capacity, node size
fn chb_prepend_bytes(dst: &mut ChbChain, data: &[u8]) {
    let size = data.len();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
    let should_create = match dst.head.front() {
        Some(nd) => {
            // Check is READONLY
            size > nd.start
        }
        None => {
            true
        }
    };
    if should_create {
        chb_create_node_head(dst, size);
    }
    // node could not be None here
    let node = dst.head.front_mut().unwrap();
    // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
    let start = node.start;
    blit(data.as_slice(), 0,
         node.dh.data.as_mut_slice(), start - size,
         size);
    node.start -= size;
    dst.length += size;
}

fn main() {
    let mut chain = chb_new();
    chb_append_bytes(&mut chain, "abcdefghijklmnop".as_bytes());
    chb_prepend_bytes(&mut chain, "xxx".as_bytes());
}
<|endoftext|>


<commit_before>//! A wrapper around a Cairo image surface.

use std::io::Write;
use std::fs::File;
use std::default::Default;

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Lua, Table,
           UserData, UserDataMethods, Value};
use wlroots::{Area, Origin, Size};
use tempfile;
use byteorder::{NativeEndian, WriteBytesExt};

use common::{class::{self, Class},
             object::{self, Object},
             property::Property};
use wayland_obj::{self, XdgToplevel};

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: XdgToplevel,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let wayland_shell = wayland_obj::create_xdg_toplevel(None)
            .expect("Could not construct an xdg toplevel for a drawable");
        // TODO Is a temp file really the best way to do this?
        let temp_file = tempfile::tempfile()
            .expect("Could not make a temp file for the buffer");
        DrawableState { temp_file,
                        wayland_shell,
                        surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    let _ = ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            let size: Size = geometry.size;

            // TODO REMOVE
            use std::cmp::*;
            let (width, height): (u32, u32) = (size.width as u32, size.height as u32);
            for i in 0..(width * height) {
                let x = (i % width) as u32;
                let y = (i / width) as u32;
                let r: u32 = min(((width - x) * 0xFF) / width, ((height  - y) * 0xFF) / height);
                let g: u32 = min((x * 0xFF) / width, ((height  - y) * 0xFF) / height);
                let b: u32 = min(((width - x) * 0xFF) / width, (y * 0xFF) / height);
                drawable.temp_file.write_u32::<NativeEndian>((0xFF << 24) + (r << 16) + (g << 8) + b).unwrap();
                }

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile()
                    .expect("Could not make new temp file");
                temp_file.set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                             size.width,
                                                             size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                drawable.wayland_shell.set_size(size);
                drawable.wayland_shell.set_surface(&temp_file, size)
                    .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                drawable.temp_file = temp_file;
                // TODO emity property::surface
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        drawable.refreshed = true;
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}
<commit_msg>Actually render the contents of the drawables<commit_after>//! A wrapper around a Cairo image surface.

use std::io::Write;
use std::fs::File;
use std::default::Default;

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Lua, Table,
           UserData, UserDataMethods, Value};
use wlroots::{Area, Origin, Size};
use tempfile;
use byteorder::{NativeEndian, WriteBytesExt};

use common::{class::{self, Class},
             object::{self, Object},
             property::Property};
use wayland_obj::{self, XdgToplevel};

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: XdgToplevel,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let wayland_shell = wayland_obj::create_xdg_toplevel(None)
            .expect("Could not construct an xdg toplevel for a drawable");
        // TODO Is a temp file really the best way to do this?
        let temp_file = tempfile::tempfile()
            .expect("Could not make a temp file for the buffer");
        DrawableState { temp_file,
                        wayland_shell,
                        surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    let _ = ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            let size: Size = geometry.size;

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile()
                    .expect("Could not make new temp file");
                temp_file.set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                             size.width,
                                                             size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                drawable.wayland_shell.set_size(size);
                drawable.wayland_shell.set_surface(&temp_file, size)
                    .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                drawable.temp_file = temp_file;
                // TODO emity property::surface
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        let drawable = &mut *drawable;
        if let Some(data) = drawable.surface.as_mut().map(get_data) {
            drawable.temp_file.write(&*data)
                .expect("Could not write data to buffer");
            drawable.temp_file.flush()
                .expect("Could not flush buffer");
            drawable.refreshed = true;
        }
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}

/// Get the data associated with the ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    use std::slice;
    use cairo_sys;
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<|endoftext|>


<commit_before>extern crate scroll;
extern crate goblin;
use goblin::archive::*;
use scroll::Pread;
use std::path::Path;
use std::fs::File;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(_) => assert!(false),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &'static str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                println!("could not get crt1.o");
                assert!(false)
            }
        },
        Err(err) => {println!("could not parse archive: {:?}", err); assert!(false)}
    };
}

#[test]
fn parse_self() {
    use std::io::Read;
    let path = Path::new("target").join("debug").join("libgoblin.rlib");
    let buffer = {
        let mut fd = File::open(path).expect("open file");
        let mut v = Vec::new();
        fd.read_to_end(&mut v).expect("read file");
        v
    };

    let archive = Archive::parse(&buffer).expect("parse rlib");

    let goblin_object_name = archive.members()
        .into_iter()
        .filter(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18
        })
        .next()
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name.as_str(), &buffer).expect("extract goblin object");
    match goblin::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
            assert!(elf.bias == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            println!("unexpected Object::parse result: {:?}", other);
            assert!(false);
        }
    }
}
<commit_msg>Test that the rlib archive contains some symbols<commit_after>extern crate scroll;
extern crate goblin;
use goblin::archive::*;
use scroll::Pread;
use std::path::Path;
use std::fs::File;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(_) => assert!(false),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &'static str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                println!("could not get crt1.o");
                assert!(false)
            }
        },
        Err(err) => {println!("could not parse archive: {:?}", err); assert!(false)}
    };
}

#[test]
fn parse_self() {
    use std::io::Read;
    let path = Path::new("target").join("debug").join("libgoblin.rlib");
    let buffer = {
        let mut fd = File::open(path).expect("open file");
        let mut v = Vec::new();
        fd.read_to_end(&mut v).expect("read file");
        v
    };

    let archive = Archive::parse(&buffer).expect("parse rlib");

    // check that the archive has a useful symbol table
    archive.summarize().into_iter()
        .filter(|&(_member_name, _member_index, ref symbols)| symbols.len() > 500)
        .next()
        .expect("archive should contain a member with at least 500 symbols");

    let goblin_object_name = archive.members()
        .into_iter()
        .filter(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18
        })
        .next()
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name.as_str(), &buffer).expect("extract goblin object");
    match goblin::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
            assert!(elf.bias == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            println!("unexpected Object::parse result: {:?}", other);
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::types::{Intern, RawInternKey};
use core::cmp::Ordering;
use fnv::FnvHashMap;
use lazy_static::lazy_static;
use parking_lot::RwLock;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::num::NonZeroU32;
use std::sync::Arc;

/// Slices of bytes intern as BytesKey
impl Intern for &[u8] {
    type Key = BytesKey;

    fn intern(self) -> Self::Key {
        BytesKey(BYTES_TABLE.intern(self))
    }
}

/// Owned strings intern as StringKey, with the interning
/// based on the raw bytes of the string
impl Intern for String {
    type Key = StringKey;

    fn intern(self) -> Self::Key {
        StringKey(BYTES_TABLE.intern(self.as_bytes()))
    }
}

/// Str (slices) intern as StringKey, with the interning
/// based on the raw bytes of the str.
impl Intern for &str {
    type Key = StringKey;

    fn intern(self) -> Self::Key {
        StringKey(BYTES_TABLE.intern(self.as_bytes()))
    }
}

/// Interned bytes
#[derive(Copy, Clone, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct BytesKey(RawInternKey);

impl BytesKey {
    pub fn lookup(self) -> &'static [u8] {
        BYTES_TABLE.lookup(self.0)
    }
}

impl fmt::Debug for BytesKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let bytes_value = self.lookup();
        write!(f, "{:?}", bytes_value)
    }
}

/// An interned string
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct StringKey(RawInternKey);

impl Ord for StringKey {
    fn cmp(&self, other: &Self) -> Ordering {
        self.lookup().cmp(&other.lookup())
    }
}

impl PartialOrd for StringKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.lookup().partial_cmp(&other.lookup())
    }
}

impl StringKey {
    /// Get a reference to the original str.
    pub fn lookup(self) -> &'static str {
        let bytes = BYTES_TABLE.lookup(self.0);
        // This is safe because the bytes we are converting originally came
        // from a str when we interned it: the only way to get a StringKey is
        // to intern an (already valid) string, so if we have a StringKey then
        // its bytes must be valid UTF-8.
        unsafe { std::str::from_utf8_unchecked(bytes) }
    }

    /// Convert the interned string key into an interned bytes key. Because
    /// strings intern as their raw bytes, this is an O(1) operation.
    /// Note the reverse (BytesKey.as_str) is a fallible operation since
    /// the bytes may not be valid UTF-8.
    pub fn as_bytes(self) -> BytesKey {
        BytesKey(self.0)
    }
}

impl fmt::Debug for StringKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let str_value = self.lookup();
        write!(f, "{:?}", str_value)
    }
}

impl fmt::Display for StringKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let str_value = self.lookup();
        write!(f, "{}", str_value)
    }
}

impl Serialize for StringKey {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.lookup())
    }
}

impl<'de> Deserialize<'de> for StringKey {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(|s: String| s.intern())
    }
}

// Static table used in the bytes/str Intern implementations
lazy_static! {
    static ref BYTES_TABLE: BytesTable = BytesTable::new();
}

/// Similar to the generic `InternTable` but customized for sequences of raw bytes (and strings).
pub struct BytesTable {
    data: Arc<RwLock<BytesTableData>>,
}

impl BytesTable {
    pub fn new() -> Self {
        Self {
            data: Arc::new(RwLock::new(BytesTableData::new())),
        }
    }

    pub fn intern(&self, value: &[u8]) -> RawInternKey {
        if let Some(prev) = self.data.read().get(&value) {
            return prev;
        }
        let mut writer = self.data.write();
        writer.intern(value)
    }

    pub fn lookup(&self, key: RawInternKey) -> &'static [u8] {
        self.data.read().lookup(key)
    }
}

/// BytesTableData is similar to InternTableData but customized for sequences
/// of raw bytes (and notably, strings).
struct BytesTableData {
    // Raw data storage, allocated in large chunks
    buffer: Option<&'static mut [u8]>,
    // Reverse mapping of index=>value, used to convert an
    // interned key back to (a reference to) its value
    items: Vec<&'static [u8]>,
    // Mapping of values to their interned indices
    table: FnvHashMap<&'static [u8], RawInternKey>,
}

impl BytesTableData {
    const BUFFER_SIZE: usize = 4096;

    pub fn new() -> Self {
        Self {
            buffer: Some(Self::new_buffer()),
            items: vec![
                // Add buffer value so the used index starts at 1
                // and we can use a NonZero type.
                b"<sentinel>",
            ],
            table: Default::default(),
        }
    }

    fn new_buffer() -> &'static mut [u8] {
        Box::leak(Box::new([0; Self::BUFFER_SIZE]))
    }

    pub fn get(&self, value: &[u8]) -> Option<RawInternKey> {
        self.table.get(value).cloned()
    }

    // Copy the byte slice into 'static memory by appending it to a buffer, if there is room.
    // If the buffer fills up and the value is small, start over with a new buffer.
    // If the value is large, just give it its own memory.
    fn alloc(&mut self, value: &[u8]) -> &'static [u8] {
        let len = value.len();

        let mut buffer = self.buffer.take().unwrap();
        if len > buffer.len() {
            if len >= Self::BUFFER_SIZE / 16 {
                // This byte slice is so big it can just have its own memory.
                self.buffer = Some(buffer);
                return Box::leak(value.into());
            } else {
                buffer = Self::new_buffer()
            }
        }

        let (mem, remaining) = buffer.split_at_mut(len);
        mem.copy_from_slice(value);
        self.buffer = Some(remaining);

        mem
    }

    pub fn intern(&mut self, value: &[u8]) -> RawInternKey {
        // If there's an existing value return it
        if let Some(prev) = self.get(&value) {
            return prev;
        }

        // Otherwise intern
        let key = RawInternKey::new(unsafe {
            // Safe because we initialize `self.items` with a sentinel value
            NonZeroU32::new_unchecked(self.items.len() as u32)
        });
        let static_bytes = self.alloc(value);
        self.items.push(static_bytes);
        self.table.insert(static_bytes, key);

        key
    }

    pub fn lookup(&self, key: RawInternKey) -> &'static [u8] {
        let index = key.as_usize();
        self.items[index]
    }
}
<commit_msg>impl FromStr for StringKey<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::types::{Intern, RawInternKey};
use core::cmp::Ordering;
use fnv::FnvHashMap;
use lazy_static::lazy_static;
use parking_lot::RwLock;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::num::NonZeroU32;
use std::str::FromStr;
use std::sync::Arc;

/// Slices of bytes intern as BytesKey
impl Intern for &[u8] {
    type Key = BytesKey;

    fn intern(self) -> Self::Key {
        BytesKey(BYTES_TABLE.intern(self))
    }
}

/// Owned strings intern as StringKey, with the interning
/// based on the raw bytes of the string
impl Intern for String {
    type Key = StringKey;

    fn intern(self) -> Self::Key {
        StringKey(BYTES_TABLE.intern(self.as_bytes()))
    }
}

/// Str (slices) intern as StringKey, with the interning
/// based on the raw bytes of the str.
impl Intern for &str {
    type Key = StringKey;

    fn intern(self) -> Self::Key {
        StringKey(BYTES_TABLE.intern(self.as_bytes()))
    }
}

/// Interned bytes
#[derive(Copy, Clone, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct BytesKey(RawInternKey);

impl BytesKey {
    pub fn lookup(self) -> &'static [u8] {
        BYTES_TABLE.lookup(self.0)
    }
}

impl fmt::Debug for BytesKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let bytes_value = self.lookup();
        write!(f, "{:?}", bytes_value)
    }
}

/// An interned string
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct StringKey(RawInternKey);

impl Ord for StringKey {
    fn cmp(&self, other: &Self) -> Ordering {
        self.lookup().cmp(&other.lookup())
    }
}

impl PartialOrd for StringKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.lookup().partial_cmp(&other.lookup())
    }
}

impl FromStr for StringKey {
    type Err = std::convert::Infallible;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(s.intern())
    }
}

impl StringKey {
    /// Get a reference to the original str.
    pub fn lookup(self) -> &'static str {
        let bytes = BYTES_TABLE.lookup(self.0);
        // This is safe because the bytes we are converting originally came
        // from a str when we interned it: the only way to get a StringKey is
        // to intern an (already valid) string, so if we have a StringKey then
        // its bytes must be valid UTF-8.
        unsafe { std::str::from_utf8_unchecked(bytes) }
    }

    /// Convert the interned string key into an interned bytes key. Because
    /// strings intern as their raw bytes, this is an O(1) operation.
    /// Note the reverse (BytesKey.as_str) is a fallible operation since
    /// the bytes may not be valid UTF-8.
    pub fn as_bytes(self) -> BytesKey {
        BytesKey(self.0)
    }
}

impl fmt::Debug for StringKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let str_value = self.lookup();
        write!(f, "{:?}", str_value)
    }
}

impl fmt::Display for StringKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let str_value = self.lookup();
        write!(f, "{}", str_value)
    }
}

impl Serialize for StringKey {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.lookup())
    }
}

impl<'de> Deserialize<'de> for StringKey {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(|s: String| s.intern())
    }
}

// Static table used in the bytes/str Intern implementations
lazy_static! {
    static ref BYTES_TABLE: BytesTable = BytesTable::new();
}

/// Similar to the generic `InternTable` but customized for sequences of raw bytes (and strings).
pub struct BytesTable {
    data: Arc<RwLock<BytesTableData>>,
}

impl BytesTable {
    pub fn new() -> Self {
        Self {
            data: Arc::new(RwLock::new(BytesTableData::new())),
        }
    }

    pub fn intern(&self, value: &[u8]) -> RawInternKey {
        if let Some(prev) = self.data.read().get(&value) {
            return prev;
        }
        let mut writer = self.data.write();
        writer.intern(value)
    }

    pub fn lookup(&self, key: RawInternKey) -> &'static [u8] {
        self.data.read().lookup(key)
    }
}

/// BytesTableData is similar to InternTableData but customized for sequences
/// of raw bytes (and notably, strings).
struct BytesTableData {
    // Raw data storage, allocated in large chunks
    buffer: Option<&'static mut [u8]>,
    // Reverse mapping of index=>value, used to convert an
    // interned key back to (a reference to) its value
    items: Vec<&'static [u8]>,
    // Mapping of values to their interned indices
    table: FnvHashMap<&'static [u8], RawInternKey>,
}

impl BytesTableData {
    const BUFFER_SIZE: usize = 4096;

    pub fn new() -> Self {
        Self {
            buffer: Some(Self::new_buffer()),
            items: vec![
                // Add buffer value so the used index starts at 1
                // and we can use a NonZero type.
                b"<sentinel>",
            ],
            table: Default::default(),
        }
    }

    fn new_buffer() -> &'static mut [u8] {
        Box::leak(Box::new([0; Self::BUFFER_SIZE]))
    }

    pub fn get(&self, value: &[u8]) -> Option<RawInternKey> {
        self.table.get(value).cloned()
    }

    // Copy the byte slice into 'static memory by appending it to a buffer, if there is room.
    // If the buffer fills up and the value is small, start over with a new buffer.
    // If the value is large, just give it its own memory.
    fn alloc(&mut self, value: &[u8]) -> &'static [u8] {
        let len = value.len();

        let mut buffer = self.buffer.take().unwrap();
        if len > buffer.len() {
            if len >= Self::BUFFER_SIZE / 16 {
                // This byte slice is so big it can just have its own memory.
                self.buffer = Some(buffer);
                return Box::leak(value.into());
            } else {
                buffer = Self::new_buffer()
            }
        }

        let (mem, remaining) = buffer.split_at_mut(len);
        mem.copy_from_slice(value);
        self.buffer = Some(remaining);

        mem
    }

    pub fn intern(&mut self, value: &[u8]) -> RawInternKey {
        // If there's an existing value return it
        if let Some(prev) = self.get(&value) {
            return prev;
        }

        // Otherwise intern
        let key = RawInternKey::new(unsafe {
            // Safe because we initialize `self.items` with a sentinel value
            NonZeroU32::new_unchecked(self.items.len() as u32)
        });
        let static_bytes = self.alloc(value);
        self.items.push(static_bytes);
        self.table.insert(static_bytes, key);

        key
    }

    pub fn lookup(&self, key: RawInternKey) -> &'static [u8] {
        let index = key.as_usize();
        self.items[index]
    }
}
<|endoftext|>


<commit_before>use rules::parse::Ast::*;
use rules::parse::Membership::*;
use rules::range_set;

use super::{new_deque, simplify};

#[test]
fn text() {
    assert_eq!(vec![Char('f'), Char('r'), Char('e'), Char('d')], simplify(r"fred"));
}
#[test]
fn empty() {
    // Set of chars inside `[]`
    let set = vec![Char('a')].into();
    // Deque of ops and sets inside `<>`
    let deque = new_deque(vec![Set(set, Inclusive)]);
    // A single class denoted by `<[]>`
    assert_eq!(vec![Class(deque.clone())], simplify(r"< + [ a ] >"));
    assert_eq!(vec![Class(deque)], simplify(r"<[ a ] + >"));
}
#[test]
fn char_class_sets() {
    // Set of chars inside `[]`
    let set   = vec![Char('a'), Char('b'), Char('c')].into();
    let empty = vec![].into();
    // Deque of ops and sets inside `<>`
    let deque      = new_deque(vec![Set(set, Inclusive)]);
    let everything = new_deque(vec![Set(empty, Exclusive)]);
    // A single class which is the union of all subsets.
    assert_eq!(vec![Class(deque)], simplify(r"< [ abab ] + [ bc ] + [ abc ] >"));
    assert_eq!(vec![Class(everything.clone())], simplify(r"< [ abc \d \D ] >"));
    assert_eq!(vec![Class(everything)], simplify(r"< [ abc ] + [ \d ] + [ \D ] >"));
}
/*
#[test]
#[should_panic]
fn char_class_set_subset_complete_overlap() {
    assert!(simplify(r"< [ 0..6 0..9 ]>");
}

#[test]
#[should_panic]
fn char_class_set_subset_partial_overlap() {
    assert!(simplify(r"< [ 0..3 2..9 ]>");
}
*/
#[test]
fn disjoint_char_class_sets() {
    // Set of chars inside `[]`
    let set   = vec![Range(range_set::Range('0', '1')), Range(range_set::Range('2', '9'))].into();
    // Deque of ops and sets inside `<>`
    let deque = new_deque(vec![Set(set, Inclusive)]);
    // A single class which is the union of all subsets.
    assert_eq!(vec![Class(deque)], simplify(r"< [ 0..3 ] + [ 2..9 ]>"));
}
#[test]
fn char_class_subset() {
    // Set of chars inside `[]`
    let set   = vec![Range(range_set::Range('0', '9'))].into();
    // Deque of ops and sets inside `<>`
    let deque = new_deque(vec![Set(set, Inclusive)]);
    // A single class which is the union of all subsets.
    assert_eq!(vec![Class(deque)], simplify(r"< [ 0..3 ] + [ 0..9 ]>"));
}
<commit_msg>Update collapse tests<commit_after>use rules::parse::Ast::*;
use rules::parse::Membership::*;

use super::{new_deque, simplify};

#[test]
fn text() {
    assert_eq!(vec![Char('f'), Char('r'), Char('e'), Char('d')], simplify(r"fred"));
}
#[test]
fn empty() {
    // Set of chars inside `[]`
    let set = vec![Char('a')].into();
    // Deque of ops and sets inside `<>`
    let deque = new_deque(vec![Set(set, Inclusive)]);
    // A single class denoted by `<[]>`
    assert_eq!(vec![Class(deque.clone())], simplify(r"< + [ a ] >"));
    assert_eq!(vec![Class(deque)], simplify(r"<[ a ] + >"));
}
#[test]
fn char_class() {
    // Set of chars inside `[]`
    let set   = vec![Char('a'), Char('b'), Char('c')].into();
    let empty = vec![].into();
    // Deque of ops and sets inside `<>`
    let deque      = new_deque(vec![Set(set, Inclusive)]);
    let everything = new_deque(vec![Set(empty, Exclusive)]);
    // A single class which is the union of all subsets.
    assert_eq!(vec![Class(deque)], simplify(r"< [ abab ] + [ bc ] + [ abc ] >"));
    assert_eq!(vec![Class(everything.clone())], simplify(r"< [ abc \d \D ] >"));
    assert_eq!(vec![Class(everything)], simplify(r"< [ abc ] + [ \d ] + [ \D ] >"));
}
<|endoftext|>


<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

extern crate serde_json;
use serde_json::value::Value;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                      vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                       "--import-way".into(),
                       "--import-admin".into(),
                       "--level=8".into(),
                       format!("--connection-string={}", es_wrapper.host())],
                       &es_wrapper);

    // Test: Import of Admin
    let res: Vec<_> = es_wrapper.search_and_filter("label:Livry-sur-Seine", |_| true).collect();
    assert_eq!(res.len(), 1);
    let city_type = res[0].pointer("/_type").and_then(|v| v.as_string());
    assert_eq!(city_type, Some("admin"));

    // Test: search for "Rue des Près"
    let search = es_wrapper.search("label:Rue des Près");
    // The first hit should be "Rue des Près"
    let street_label = search.pointer("/hits/hits/0/_source/label").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(street_label, "Rue des Près");
    // And there should be only ONE "Rue des Près"
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        label == "Rue des Près"
    };
    let nb = es_wrapper.search_and_filter(r#"label:Rue des Près"#, street_filter).count();
    assert_eq!(nb, 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
        label == "Rue du Four à Chaux" && admin_label == "Livry-sur-Seine"
    };
    let nb = es_wrapper.search_and_filter("label:Rue du Four à Chaux", street_filter).count();
    assert_eq!(nb, 6);

    //Test: Streets having the same label in different cities
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
        label == r#"Rue du Port"# && admin_label == r#"Melun"#
    };
    let nb = es_wrapper.search_and_filter(r#"label:Rue du Port"#, street_filter).count();
    assert_eq!(nb, 1);
}
<commit_msg>remove raw string<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

extern crate serde_json;
use serde_json::value::Value;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                      vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                       "--import-way".into(),
                       "--import-admin".into(),
                       "--level=8".into(),
                       format!("--connection-string={}", es_wrapper.host())],
                       &es_wrapper);

    // Test: Import of Admin
    let res: Vec<_> = es_wrapper.search_and_filter("label:Livry-sur-Seine", |_| true).collect();
    assert_eq!(res.len(), 1);
    let city_type = res[0].pointer("/_type").and_then(|v| v.as_string());
    assert_eq!(city_type, Some("admin"));

    // Test: search for "Rue des Près"
    let search = es_wrapper.search("label:Rue des Près");
    // The first hit should be "Rue des Près"
    let street_label = search.pointer("/hits/hits/0/_source/label").and_then(|v| v.as_string()).unwrap_or("");
    assert_eq!(street_label, "Rue des Près");
    // And there should be only ONE "Rue des Près"
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        label == "Rue des Près"
    };
    let nb = es_wrapper.search_and_filter("label:Rue des Près", street_filter).count();
    assert_eq!(nb, 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
        label == "Rue du Four à Chaux" && admin_label == "Livry-sur-Seine"
    };
    let nb = es_wrapper.search_and_filter("label:Rue du Four à Chaux", street_filter).count();
    assert_eq!(nb, 6);

    //Test: Streets having the same label in different cities
    let street_filter = |street: &Value| {
        let label = street.pointer("/_source/label").and_then(|n| n.as_string()).unwrap_or("");
        let admin_label = street.pointer("/_source/administrative_regions/0/label").and_then(|n| n.as_string()).unwrap_or("");
        label == "Rue du Port" && admin_label == "Melun"
    };
    let nb = es_wrapper.search_and_filter("label:Rue du Port", street_filter).count();
    assert_eq!(nb, 1);
}
<|endoftext|>