<commit_before>use rusqlite as rs;
use slack_api as slack;

use chrono::prelude::{Utc, DateTime};

use tokio::sync::mpsc;

use crate::bot::parser::karma::Karma;
use crate::bot::parser::reacji_to_karma;

use crate::bot::query::santizer;
use crate::bot::query::{KarmaName, ReacjiAction};

use crate::core::cache;

use crate::core::database::DbResult;
use crate::core::database::Query;
use crate::core::database::send_query;

pub async fn add_reacji<R>(
    sql_tx: &mut mpsc::Sender<Query>,
    cache: &cache::Cache<R>,
    input: &str,
    user_id: String,
    channel_id: String,
    ts: String,
    action: ReacjiAction,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    match reacji_to_karma(input) {
        Some(karma) => {
            let message_id = query_reacji_message(
                sql_tx,
                channel_id.clone(),
                ts.clone()
            ).await.ok().flatten();

            let message_id = match message_id {
                None => {
                    match cache.get_message(&channel_id, &ts).await {
                        Some(cache::ConversationHistoryMessage::Message { text, user_id: Some(user_id) }) => {
                            // We have the message content, insert it into the table and
                            // get its row id
                            let santized_text = santizer(&text, &cache).await;

                            match (
                                cache.get_username(&user_id).await,
                                cache.get_user_real_name(&user_id).await,
                            ) {
                                (Some(ud), Some(rn)) => {
                                    add_reacji_message(
                                        sql_tx,
                                        user_id,
                                        KarmaName::new(&ud),
                                        KarmaName::new(&rn),
                                        channel_id.clone(),
                                        ts.clone(),
                                        santized_text
                                    ).await.ok().flatten()
                                },
                                _ => {
                                    eprintln!("ERROR: [User Event] Wasn't able to get a username/real_name from slack");
                                    None
                                },
                            }
                        },
                        // This should already have been logged by the api call function
                        _ => None,
                    }
                },
                Some(mid) => Some(mid),
            };

            match message_id {
                None => eprintln!(
                    "ERROR: [User Event] Wasn't able to get/store an reactji message, vote isn't recorded"
                ),
                Some(mid) => {
                    match (
                        cache.get_username(&user_id).await,
                        cache.get_user_real_name(&user_id).await,
                    ) {
                        (Some(ud), Some(rn)) => {
                            let _ = add_reacji_query(
                                sql_tx,
                                Utc::now(),
                                user_id,
                                KarmaName::new(&ud),
                                KarmaName::new(&rn),
                                action,
                                mid,
                                karma,
                            ).await;
                        },
                        _ => eprintln!("ERROR: [User Event] Wasn't able to get a username/real_name from slack"),
                    }
                },
            }
        },
        None => (),
    }
}

async fn query_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    channel_id: String,
    message_ts: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let channel_id: Option<i64> = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0).ok()
                } else {
                    None
                }
            };

            if let Some(channel_id) = channel_id {
                // We good let's proceed, otherwise abort since if channel id isn't here its
                // not going to be in reacji_message either
                let mut stmt = conn.prepare("SELECT id FROM reacji_message WHERE ts = ? AND chan_id = ?")?;
                let mut rows = stmt.query(rs::params![message_ts, channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    let msg_id: Option<i64> = row.get(0).ok();
                    Ok(msg_id)
                } else {
                    Ok(None)
                }
            } else {
                Ok(None)
            }
        })
    ).await
}

async fn add_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    channel_id: String,
    message_ts: String,
    message: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;
                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let channel_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare("INSERT INTO chan_metadata (channel) VALUES (?)")?;
                    stmt.insert(rs::params![channel_id])?
                }
            };

            // Insert the reacji_message content now
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_message (ts, chan_id, nick_id, message) VALUES (?, ?, ?, ?)"
            )?;

            Ok(
                Some(stmt.insert(rs::params![message_ts, channel_id, nick_id, message])?)
            )
        })
    ).await
}

async fn add_reacji_query(
    sql_tx: &mut mpsc::Sender<Query>,
    timestamp: DateTime<Utc>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    action: ReacjiAction,
    message_id: i64,
    amount: Karma,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;

                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let ts = timestamp.to_rfc3339();
            let ts = ts.trim_end_matches("+00:00");

            // Insert the reacji into the database
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_votes
                    (voted_at, by_whom_name, action, reacji_message_id, amount, nick_id)
                VALUES
                    (?, ?, ?, ?, ?, ?)"
            )?;

            stmt.insert(rs::params![ts, username, action, message_id, amount, nick_id])?;

            Ok(None)
        })
    ).await
}
<commit_msg>Improve reacji debugging<commit_after>use rusqlite as rs;
use slack_api as slack;

use chrono::prelude::{Utc, DateTime};

use tokio::sync::mpsc;

use crate::bot::parser::karma::Karma;
use crate::bot::parser::reacji_to_karma;

use crate::bot::query::santizer;
use crate::bot::query::{KarmaName, ReacjiAction};

use crate::core::cache;

use crate::core::database::DbResult;
use crate::core::database::Query;
use crate::core::database::send_query;

fn fix<T>(input: Result<Option<T>, String>) -> Result<T, String> {
    input.map_or_else(
        |e| Err(e),
        |v| v.ok_or("NONE RESULT".to_string())
    )
}

pub async fn add_reacji<R>(
    sql_tx: &mut mpsc::Sender<Query>,
    cache: &cache::Cache<R>,
    input: &str,
    user_id: String,
    channel_id: String,
    ts: String,
    action: ReacjiAction,
)
where
    R: slack::requests::SlackWebRequestSender + std::clone::Clone
{
    match reacji_to_karma(input) {
        Some(karma) => {
            let message_id = fix(query_reacji_message(
                sql_tx,
                channel_id.clone(),
                ts.clone()
            ).await);

            let message_id = match message_id {
                Err(e) => {
                    eprintln!("ERROR: [User Event] Querying for reacji failed: {:?}", e);

                    fix(match cache.get_message(&channel_id, &ts).await {
                        Some(cache::ConversationHistoryMessage::Message { text, user_id: Some(user_id) }) => {
                            // We have the message content, insert it into the table and
                            // get its row id
                            let santized_text = santizer(&text, &cache).await;

                            match (
                                cache.get_username(&user_id).await,
                                cache.get_user_real_name(&user_id).await,
                            ) {
                                (Some(ud), Some(rn)) => {
                                    add_reacji_message(
                                        sql_tx,
                                        user_id,
                                        KarmaName::new(&ud),
                                        KarmaName::new(&rn),
                                        channel_id.clone(),
                                        ts.clone(),
                                        santized_text
                                    ).await
                                },
                                e => Err(format!("ERROR: [User Event] Querying for user/name failed: {:?}", e)),
                            }
                        },
                        // This should already have been logged by the api call function
                        e => Err(format!("ERROR: [User Event] IDK here: {:?}", e)),
                    })
                },
                Ok(mid) => Ok(mid),
            };

            match message_id {
                Err(e) => {
                    eprintln!("ERROR: [User Event] Wasn't able to get/store an reactji message, vote isn't recorded");
                    eprintln!("ERROR: [User Event] Returned error: {:?}", e);
                },
                Ok(mid) => {
                    match (
                        cache.get_username(&user_id).await,
                        cache.get_user_real_name(&user_id).await,
                    ) {
                        (Some(ud), Some(rn)) => {
                            let e = add_reacji_query(
                                sql_tx,
                                Utc::now(),
                                user_id,
                                KarmaName::new(&ud),
                                KarmaName::new(&rn),
                                action,
                                mid,
                                karma,
                            ).await;

                            if e.is_err() {
                                eprintln!("ERROR: [User Event] Query failed: {:?}", e);
                            }
                        },
                        e => eprintln!("ERROR: [User Event] Querying for user/name failed: {:?}", e),
                    }
                },
            }
        },
        None => (),
    }
}

async fn query_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    channel_id: String,
    message_ts: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let channel_id: Option<i64> = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0).ok()
                } else {
                    None
                }
            };

            if let Some(channel_id) = channel_id {
                // We good let's proceed, otherwise abort since if channel id isn't here its
                // not going to be in reacji_message either
                let mut stmt = conn.prepare("SELECT id FROM reacji_message WHERE ts = ? AND chan_id = ?")?;
                let mut rows = stmt.query(rs::params![message_ts, channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    let msg_id: Option<i64> = row.get(0).ok();
                    Ok(msg_id)
                } else {
                    Ok(None)
                }
            } else {
                Ok(None)
            }
        })
    ).await
}

async fn add_reacji_message(
    sql_tx: &mut mpsc::Sender<Query>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    channel_id: String,
    message_ts: String,
    message: String,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;
                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let channel_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM chan_metadata WHERE channel = ?")?;
                let mut rows = stmt.query(rs::params![channel_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare("INSERT INTO chan_metadata (channel) VALUES (?)")?;
                    stmt.insert(rs::params![channel_id])?
                }
            };

            // Insert the reacji_message content now
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_message (ts, chan_id, nick_id, message) VALUES (?, ?, ?, ?)"
            )?;

            Ok(
                Some(stmt.insert(rs::params![message_ts, channel_id, nick_id, message])?)
            )
        })
    ).await
}

async fn add_reacji_query(
    sql_tx: &mut mpsc::Sender<Query>,
    timestamp: DateTime<Utc>,
    user_id: String,
    username: KarmaName,
    real_name: KarmaName,
    action: ReacjiAction,
    message_id: i64,
    amount: Karma,
) -> DbResult<Option<i64>> {
    send_query(
        sql_tx,
        Box::new(move |conn: &mut rs::Connection| {
            let nick_id: i64 = {
                let mut stmt = conn.prepare("SELECT id FROM nick_metadata WHERE username = ?")?;
                let mut rows = stmt.query(rs::params![user_id])?;

                if let Ok(Some(row)) = rows.next() {
                    row.get(0)?
                } else {
                    let mut stmt = conn.prepare(
                        "INSERT INTO nick_metadata (cleaned_nick, full_name, username, hostmask) VALUES (?, ?, ?, ?)"
                    )?;

                    stmt.insert(rs::params![username, real_name, user_id, "SlackServer"])?
                }
            };

            let ts = timestamp.to_rfc3339();
            let ts = ts.trim_end_matches("+00:00");

            // Insert the reacji into the database
            let mut stmt = conn.prepare(
                "INSERT INTO reacji_votes
                    (voted_at, by_whom_name, action, reacji_message_id, amount, nick_id)
                VALUES
                    (?, ?, ?, ?, ?, ?)"
            )?;

            stmt.insert(rs::params![ts, username, action, message_id, amount, nick_id])?;

            Ok(None)
        })
    ).await
}
<|endoftext|>


<commit_before>pub use self::imp::read2;

#[cfg(unix)]
mod imp {
    use std::io::prelude::*;
    use std::io;
    use std::mem;
    use std::os::unix::prelude::*;
    use std::process::{ChildStdout, ChildStderr};
    use libc;

    pub fn read2(mut out_pipe: ChildStdout,
                 mut err_pipe: ChildStderr,
                 data: &mut FnMut(bool, &mut Vec<u8>, bool)) -> io::Result<()> {
        unsafe {
            libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
            libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
        }

        let mut out_done = false;
        let mut err_done = false;
        let mut out = Vec::new();
        let mut err = Vec::new();

        let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
        fds[0].fd = out_pipe.as_raw_fd();
        fds[0].events = libc::POLLIN;
        fds[1].fd = err_pipe.as_raw_fd();
        fds[1].events = libc::POLLIN;
        loop {
            // wait for either pipe to become readable using `select`
            let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) };
            if r == -1 {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::Interrupted {
                    continue
                }
                return Err(err)
            }

            // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
            // EAGAIN. If we hit EOF, then this will happen because the underlying
            // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
            // this case we flip the other fd back into blocking mode and read
            // whatever's leftover on that file descriptor.
            let handle = |res: io::Result<_>| {
                match res {
                    Ok(_) => Ok(true),
                    Err(e) => {
                        if e.kind() == io::ErrorKind::WouldBlock {
                            Ok(false)
                        } else {
                            Err(e)
                        }
                    }
                }
            };
            if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
                out_done = true;
            }
            data(true, &mut out, out_done);
            if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
                err_done = true;
            }
            data(false, &mut err, err_done);

            if out_done && err_done {
                return Ok(())
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate miow;
    extern crate winapi;

    use std::io;
    use std::os::windows::prelude::*;
    use std::process::{ChildStdout, ChildStderr};
    use std::slice;

    use self::miow::iocp::{CompletionPort, CompletionStatus};
    use self::miow::pipe::NamedPipe;
    use self::miow::Overlapped;
    use self::winapi::shared::winerror::ERROR_BROKEN_PIPE;

    struct Pipe<'a> {
        dst: &'a mut Vec<u8>,
        overlapped: Overlapped,
        pipe: NamedPipe,
        done: bool,
    }

    pub fn read2(out_pipe: ChildStdout,
                 err_pipe: ChildStderr,
                 data: &mut FnMut(bool, &mut Vec<u8>, bool)) -> io::Result<()> {
        let mut out = Vec::new();
        let mut err = Vec::new();

        let port = CompletionPort::new(1)?;
        port.add_handle(0, &out_pipe)?;
        port.add_handle(1, &err_pipe)?;

        unsafe {
            let mut out_pipe = Pipe::new(out_pipe, &mut out);
            let mut err_pipe = Pipe::new(err_pipe, &mut err);

            out_pipe.read()?;
            err_pipe.read()?;

            let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];

            while !out_pipe.done || !err_pipe.done {
                for status in port.get_many(&mut status, None)? {
                    if status.token() == 0 {
                        out_pipe.complete(status);
                        data(true, out_pipe.dst, out_pipe.done);
                        out_pipe.read()?;
                    } else {
                        err_pipe.complete(status);
                        data(false, err_pipe.dst, err_pipe.done);
                        err_pipe.read()?;
                    }
                }
            }

            Ok(())
        }
    }

    impl<'a> Pipe<'a> {
        unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
            Pipe {
                dst: dst,
                pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
                overlapped: Overlapped::zero(),
                done: false,
            }
        }

        unsafe fn read(&mut self) -> io::Result<()> {
            let dst = slice_to_end(self.dst);
            match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
                Ok(_) => Ok(()),
                Err(e) => {
                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
                        self.done = true;
                        Ok(())
                    } else {
                        Err(e)
                    }
                }
            }
        }

        unsafe fn complete(&mut self, status: &CompletionStatus) {
            let prev = self.dst.len();
            self.dst.set_len(prev + status.bytes_transferred() as usize);
            if status.bytes_transferred() == 0 {
                self.done = true;
            }
        }
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}
<commit_msg>Auto merge of #5030 - alexcrichton:better-poll, r=matklad<commit_after>pub use self::imp::read2;

#[cfg(unix)]
mod imp {
    use std::io::prelude::*;
    use std::io;
    use std::mem;
    use std::os::unix::prelude::*;
    use std::process::{ChildStdout, ChildStderr};
    use libc;

    pub fn read2(mut out_pipe: ChildStdout,
                 mut err_pipe: ChildStderr,
                 data: &mut FnMut(bool, &mut Vec<u8>, bool)) -> io::Result<()> {
        unsafe {
            libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
            libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
        }

        let mut out_done = false;
        let mut err_done = false;
        let mut out = Vec::new();
        let mut err = Vec::new();

        let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
        fds[0].fd = out_pipe.as_raw_fd();
        fds[0].events = libc::POLLIN;
        fds[1].fd = err_pipe.as_raw_fd();
        fds[1].events = libc::POLLIN;
        let mut nfds = 2;
        let mut errfd = 1;

        while nfds > 0 {
            // wait for either pipe to become readable using `select`
            let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
            if r == -1 {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::Interrupted {
                    continue
                }
                return Err(err)
            }

            // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
            // EAGAIN. If we hit EOF, then this will happen because the underlying
            // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
            // this case we flip the other fd back into blocking mode and read
            // whatever's leftover on that file descriptor.
            let handle = |res: io::Result<_>| {
                match res {
                    Ok(_) => Ok(true),
                    Err(e) => {
                        if e.kind() == io::ErrorKind::WouldBlock {
                            Ok(false)
                        } else {
                            Err(e)
                        }
                    }
                }
            };
            if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
                err_done = true;
                nfds -= 1;
            }
            data(false, &mut err, err_done);
            if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
                out_done = true;
                fds[0].fd = err_pipe.as_raw_fd();
                errfd = 0;
                nfds -= 1;
            }
            data(true, &mut out, out_done);
        }
        Ok(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate miow;
    extern crate winapi;

    use std::io;
    use std::os::windows::prelude::*;
    use std::process::{ChildStdout, ChildStderr};
    use std::slice;

    use self::miow::iocp::{CompletionPort, CompletionStatus};
    use self::miow::pipe::NamedPipe;
    use self::miow::Overlapped;
    use self::winapi::shared::winerror::ERROR_BROKEN_PIPE;

    struct Pipe<'a> {
        dst: &'a mut Vec<u8>,
        overlapped: Overlapped,
        pipe: NamedPipe,
        done: bool,
    }

    pub fn read2(out_pipe: ChildStdout,
                 err_pipe: ChildStderr,
                 data: &mut FnMut(bool, &mut Vec<u8>, bool)) -> io::Result<()> {
        let mut out = Vec::new();
        let mut err = Vec::new();

        let port = CompletionPort::new(1)?;
        port.add_handle(0, &out_pipe)?;
        port.add_handle(1, &err_pipe)?;

        unsafe {
            let mut out_pipe = Pipe::new(out_pipe, &mut out);
            let mut err_pipe = Pipe::new(err_pipe, &mut err);

            out_pipe.read()?;
            err_pipe.read()?;

            let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];

            while !out_pipe.done || !err_pipe.done {
                for status in port.get_many(&mut status, None)? {
                    if status.token() == 0 {
                        out_pipe.complete(status);
                        data(true, out_pipe.dst, out_pipe.done);
                        out_pipe.read()?;
                    } else {
                        err_pipe.complete(status);
                        data(false, err_pipe.dst, err_pipe.done);
                        err_pipe.read()?;
                    }
                }
            }

            Ok(())
        }
    }

    impl<'a> Pipe<'a> {
        unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
            Pipe {
                dst: dst,
                pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
                overlapped: Overlapped::zero(),
                done: false,
            }
        }

        unsafe fn read(&mut self) -> io::Result<()> {
            let dst = slice_to_end(self.dst);
            match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
                Ok(_) => Ok(()),
                Err(e) => {
                    if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
                        self.done = true;
                        Ok(())
                    } else {
                        Err(e)
                    }
                }
            }
        }

        unsafe fn complete(&mut self, status: &CompletionStatus) {
            let prev = self.dst.len();
            self.dst.set_len(prev + status.bytes_transferred() as usize);
            if status.bytes_transferred() == 0 {
                self.done = true;
            }
        }
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}
<|endoftext|>


<commit_before>use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;

pub struct RoomGen {
    rand_x: XorShiftRng,
    rand_y: XorShiftRng,
    max_room_size: usize,
    min_room_size: usize,
    attempts: u64,
}
<commit_msg>roomgen started<commit_after>use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;

use na::Vec2;

use level::Level;

pub struct RoomGen {
    rand_x: XorShiftRng,
    rand_y: XorShiftRng,
    max_room_size: usize,
    min_room_size: usize,
    attempts: u64,
}

impl RoomGen {
    pub fn new(min_room_size: usize, max_room_size: usize, room_distance: u32, attempts :u64) -> RoomGen {
        RoomGen{
            rand_x: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            rand_y: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            max_room_size: max_room_size,
            min_room_size: min_room_size,
            attempts: attempts,
        }
    }

    pub fn generate(&mut self, level: &mut Level) {
        let mut rooms = Vec::new();
        for i in 0..self.attempts {
            let room = Self::generate_box(level);

            let fits = !self.check_collisions();
            if fits {
                rooms.append(room);
            }
        }
    }

    pub fn generate_box(level: &mut Level) -> Box {
    }
}

struct Box {
    pub min: Vec2<isize>,
    pub max:Vec2<isize>,
}
<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    gpu::arc::{ArcTexture, ArcTextureView},
    Rect,
};
use crate::{Context, GameError, GameResult};
use std::path::Path;
use std::{io::Read, num::NonZeroU32};

// maintaing a massive enum of all possible texture formats?
// screw that.
/// Describes the pixel format of an image.
pub type ImageFormat = wgpu::TextureFormat;

/// Handle to an image stored in GPU memory.
#[derive(Debug, Clone)]
pub struct Image {
    pub(crate) texture: ArcTexture,
    pub(crate) view: ArcTextureView,
    pub(crate) format: ImageFormat,
    pub(crate) width: u32,
    pub(crate) height: u32,
    pub(crate) samples: u32,
}

impl Image {
    /// Creates a new image specifically for use with a [Canvas].
    pub fn new_canvas_image(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
    ) -> Self {
        Self::new(
            gfx,
            format.into(),
            width,
            height,
            samples,
            wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
        )
    }

    /// Creates a new image initialized with given pixel data.
    pub fn from_pixels(
        gfx: &GraphicsContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        let image = Self::new(
            gfx,
            format.into(),
            width,
            height,
            1,
            wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING,
        );

        gfx.queue.write_texture(
            image.texture.as_image_copy(),
            pixels,
            wgpu::ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(
                    NonZeroU32::new(format.describe().block_size as u32 * width).unwrap(),
                ),
                rows_per_image: None,
            },
            wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
        );

        image
    }

    /// Creates a new image initialized with pixel data loaded from an encoded image `Read` (e.g. PNG or JPEG).
    #[allow(unused_results)]
    pub fn from_path(ctx: &Context, path: impl AsRef<Path>, srgb: bool) -> GameResult<Self> {
        let mut encoded = Vec::new();
        ctx.filesystem.open(path)?.read_to_end(&mut encoded)?;
        let decoded = image::load_from_memory(&encoded[..])
            .map_err(|_| GameError::ResourceLoadError(String::from("failed to load image")))?;
        let rgba8 = decoded.to_rgba8();
        let (width, height) = (rgba8.width(), rgba8.height());

        Ok(Self::from_pixels(
            &ctx.gfx,
            rgba8.as_ref(),
            if srgb {
                ImageFormat::Rgba8UnormSrgb
            } else {
                ImageFormat::Rgba8Unorm
            },
            width,
            height,
        ))
    }

    fn new(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
        usage: wgpu::TextureUsages,
    ) -> Self {
        assert!(width > 0);
        assert!(height > 0);
        assert!(samples > 0);

        let texture = ArcTexture::new(gfx.device.create_texture(&wgpu::TextureDescriptor {
            label: None,
            size: wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: samples,
            dimension: wgpu::TextureDimension::D2,
            format: format.into(),
            usage,
        }));

        let view =
            ArcTextureView::new(texture.as_ref().create_view(&wgpu::TextureViewDescriptor {
                label: None,
                format: Some(format.into()),
                dimension: Some(wgpu::TextureViewDimension::D2),
                aspect: wgpu::TextureAspect::All,
                base_mip_level: 0,
                mip_level_count: Some(NonZeroU32::new(1).unwrap()),
                base_array_layer: 0,
                array_layer_count: Some(NonZeroU32::new(1).unwrap()),
            }));

        Image {
            texture,
            view,
            format,
            width,
            height,
            samples,
        }
    }

    /// Returns the image format of this image.
    #[inline]
    pub fn format(&self) -> ImageFormat {
        self.format
    }

    /// Returns the number of MSAA samples this image has.
    #[inline]
    pub fn samples(&self) -> u32 {
        self.samples
    }

    /// Returns the width (in pixels) of the image.
    #[inline]
    pub fn width(&self) -> u32 {
        self.width
    }

    /// Returns the height (in pixels) of the image.
    #[inline]
    pub fn height(&self) -> u32 {
        self.height
    }

    /// Helper function that calculates a sub-rectangle of this image in UV coordinates, given pixel coordinates.
    pub fn uv_rect(&self, x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x as f32 / self.width as f32,
            y: y as f32 / self.height as f32,
            w: w as f32 / self.width as f32,
            h: h as f32 / self.height as f32,
        }
    }
}

/// An image which is sized relative to the screen.
/// This is primarily for canvas images.
#[derive(Debug, Clone)]
pub struct ScreenImage {
    image: Image,
    format: wgpu::TextureFormat,
    size: (f32, f32),
    samples: u32,
}

impl ScreenImage {
    /// Creates a new [ScreenImage] with the given parameters.
    ///
    /// `width` and `height` specify the fraction of the framebuffer width and height that the [Image] will have.
    /// For example, `width = 1.0` and `height = 1.0` means the image will be the same size as the framebuffer.
    ///
    /// If `format` is `None` then the format will be inferred from the surface format.
    pub fn new(
        gfx: &GraphicsContext,
        format: impl Into<Option<ImageFormat>>,
        width: f32,
        height: f32,
        samples: u32,
    ) -> Self {
        assert!(width > 0.);
        assert!(height > 0.);
        assert!(samples > 0);

        let format = format
            .into()
            .map(|x| x.into())
            .unwrap_or(gfx.surface_format);

        ScreenImage {
            image: Self::create(gfx, format, (width, height), samples),
            format,
            size: (width, height),
            samples,
        }
    }

    /// Returns the inner [Image], also recreating it if the framebuffer has been resized.
    pub fn image(&mut self, gfx: &GraphicsContext) -> Image {
        if Self::size(gfx, self.size) != (self.image.width(), self.image.height()) {
            self.image = Self::create(gfx, self.format, self.size, self.samples);
        }
        self.image.clone()
    }

    fn size(gfx: &GraphicsContext, (width, height): (f32, f32)) -> (u32, u32) {
        let size = gfx.window.inner_size();
        let width = (size.width as f32 * width) as u32;
        let height = (size.height as f32 * height) as u32;
        (width, height)
    }

    fn create(
        gfx: &GraphicsContext,
        format: wgpu::TextureFormat,
        size: (f32, f32),
        samples: u32,
    ) -> Image {
        let (width, height) = Self::size(gfx, size);
        Image::new(
            gfx,
            format,
            width,
            height,
            samples,
            wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
        )
    }
}
<commit_msg>impl image readback and encoding<commit_after>//!

use super::{
    context::GraphicsContext,
    gpu::arc::{ArcTexture, ArcTextureView},
    Color, Rect,
};
use crate::{Context, GameError, GameResult};
use std::path::Path;
use std::{io::Read, num::NonZeroU32};

// maintaing a massive enum of all possible texture formats?
// screw that.
/// Describes the pixel format of an image.
pub type ImageFormat = wgpu::TextureFormat;

/// Describes the format of an encoded image.
pub type ImageEncodingFormat = ::image::ImageFormat;

/// Handle to an image stored in GPU memory.
#[derive(Debug, Clone)]
pub struct Image {
    pub(crate) texture: ArcTexture,
    pub(crate) view: ArcTextureView,
    pub(crate) format: ImageFormat,
    pub(crate) width: u32,
    pub(crate) height: u32,
    pub(crate) samples: u32,
}

impl Image {
    /// Creates a new image specifically for use with a [Canvas].
    pub fn new_canvas_image(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
    ) -> Self {
        Self::new(
            gfx,
            format.into(),
            width,
            height,
            samples,
            wgpu::TextureUsages::RENDER_ATTACHMENT
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        )
    }

    /// Creates a new image initialized with given pixel data.
    pub fn from_pixels(
        gfx: &GraphicsContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        let image = Self::new(
            gfx,
            format.into(),
            width,
            height,
            1,
            wgpu::TextureUsages::COPY_DST
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        );

        gfx.queue.write_texture(
            image.texture.as_image_copy(),
            pixels,
            wgpu::ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(
                    NonZeroU32::new(format.describe().block_size as u32 * width).unwrap(),
                ),
                rows_per_image: None,
            },
            wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
        );

        image
    }

    /// A little helper function that creates a new `Image` that is just a solid square of the given size and color. Mainly useful for debugging.
    pub fn from_solid(gfx: &GraphicsContext, size: u32, color: Color) -> Self {
        let pixels = (0..(size * size))
            .map(|_| {
                let (r, g, b, a) = color.to_rgba();
                [r, g, b, a]
            })
            .flatten()
            .collect::<Vec<_>>();
        Self::from_pixels(
            gfx,
            &pixels,
            wgpu::TextureFormat::Rgba8UnormSrgb,
            size,
            size,
        )
    }

    /// Creates a new image initialized with pixel data loaded from an encoded image `Read` (e.g. PNG or JPEG).
    #[allow(unused_results)]
    pub fn from_path(ctx: &Context, path: impl AsRef<Path>, srgb: bool) -> GameResult<Self> {
        let mut encoded = Vec::new();
        ctx.filesystem.open(path)?.read_to_end(&mut encoded)?;
        let decoded = image::load_from_memory(&encoded[..])
            .map_err(|_| GameError::ResourceLoadError(String::from("failed to load image")))?;
        let rgba8 = decoded.to_rgba8();
        let (width, height) = (rgba8.width(), rgba8.height());

        Ok(Self::from_pixels(
            &ctx.gfx,
            rgba8.as_ref(),
            if srgb {
                ImageFormat::Rgba8UnormSrgb
            } else {
                ImageFormat::Rgba8Unorm
            },
            width,
            height,
        ))
    }

    fn new(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
        usage: wgpu::TextureUsages,
    ) -> Self {
        assert!(width > 0);
        assert!(height > 0);
        assert!(samples > 0);

        let texture = ArcTexture::new(gfx.device.create_texture(&wgpu::TextureDescriptor {
            label: None,
            size: wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: samples,
            dimension: wgpu::TextureDimension::D2,
            format: format.into(),
            usage,
        }));

        let view =
            ArcTextureView::new(texture.as_ref().create_view(&wgpu::TextureViewDescriptor {
                label: None,
                format: Some(format.into()),
                dimension: Some(wgpu::TextureViewDimension::D2),
                aspect: wgpu::TextureAspect::All,
                base_mip_level: 0,
                mip_level_count: Some(NonZeroU32::new(1).unwrap()),
                base_array_layer: 0,
                array_layer_count: Some(NonZeroU32::new(1).unwrap()),
            }));

        Image {
            texture,
            view,
            format,
            width,
            height,
            samples,
        }
    }

    /// Reads the pixels of this `ImageView` and returns as `Vec<u8>`.
    /// The format matches the GPU image format.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn to_pixels(&self, gfx: &GraphicsContext) -> GameResult<Vec<u8>> {
        let block_size = self.format.describe().block_size as u64;

        let buffer = gfx.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: block_size * self.width as u64 * self.height as u64,
            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
            mapped_at_creation: false,
        });

        let cmd = {
            let mut encoder = gfx
                .device
                .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
            encoder.copy_texture_to_buffer(
                self.texture.as_image_copy(),
                wgpu::ImageCopyBuffer {
                    buffer: &buffer,
                    layout: wgpu::ImageDataLayout {
                        offset: 0,
                        bytes_per_row: Some(
                            NonZeroU32::new(block_size as u32 * self.width).unwrap(),
                        ),
                        rows_per_image: None,
                    },
                },
                wgpu::Extent3d {
                    width: self.width,
                    height: self.height,
                    depth_or_array_layers: 1,
                },
            );
            encoder.finish()
        };

        gfx.queue.submit([cmd]);

        // wait...
        let fut = buffer.slice(..).map_async(wgpu::MapMode::Read);
        gfx.device.poll(wgpu::Maintain::Wait);
        pollster::block_on(fut)?;

        let out = buffer.slice(..).get_mapped_range().to_vec();
        Ok(out)
    }

    /// Encodes the `ImageView` to the given file format and return the encoded bytes.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn encode(
        &self,
        ctx: &Context,
        format: ImageEncodingFormat,
        path: impl AsRef<std::path::Path>,
    ) -> GameResult {
        let color = match self.format {
            ImageFormat::Rgba8Unorm | ImageFormat::Rgba8UnormSrgb => ::image::ColorType::Rgba8,
            ImageFormat::Bgra8Unorm | ImageFormat::Bgra8UnormSrgb => ::image::ColorType::Bgra8,
            ImageFormat::R8Unorm => ::image::ColorType::L8,
            ImageFormat::R16Unorm => ::image::ColorType::L16,
            format => {
                return Err(GameError::RenderError(format!(
                    "cannot ImageView::encode for the {:#?} GPU image format",
                    format
                )))
            }
        };

        let pixels = self.to_pixels(&ctx.gfx)?;
        let f = ctx.filesystem.create(path)?;
        let writer = &mut std::io::BufWriter::new(f);

        match format {
            ImageEncodingFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            ImageEncodingFormat::Bmp => ::image::bmp::BmpEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            _ => Err(GameError::RenderError(String::from(
                "cannot ImageView::encode for formats other than Png and Bmp",
            ))),
        }
    }

    /// Returns the image format of this image.
    #[inline]
    pub fn format(&self) -> ImageFormat {
        self.format
    }

    /// Returns the number of MSAA samples this image has.
    #[inline]
    pub fn samples(&self) -> u32 {
        self.samples
    }

    /// Returns the width (in pixels) of the image.
    #[inline]
    pub fn width(&self) -> u32 {
        self.width
    }

    /// Returns the height (in pixels) of the image.
    #[inline]
    pub fn height(&self) -> u32 {
        self.height
    }

    /// Helper function that calculates a sub-rectangle of this image in UV coordinates, given pixel coordinates.
    pub fn uv_rect(&self, x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x as f32 / self.width as f32,
            y: y as f32 / self.height as f32,
            w: w as f32 / self.width as f32,
            h: h as f32 / self.height as f32,
        }
    }
}

/// An image which is sized relative to the screen.
/// This is primarily for canvas images.
#[derive(Debug, Clone)]
pub struct ScreenImage {
    image: Image,
    format: wgpu::TextureFormat,
    size: (f32, f32),
    samples: u32,
}

impl ScreenImage {
    /// Creates a new [ScreenImage] with the given parameters.
    ///
    /// `width` and `height` specify the fraction of the framebuffer width and height that the [Image] will have.
    /// For example, `width = 1.0` and `height = 1.0` means the image will be the same size as the framebuffer.
    ///
    /// If `format` is `None` then the format will be inferred from the surface format.
    pub fn new(
        gfx: &GraphicsContext,
        format: impl Into<Option<ImageFormat>>,
        width: f32,
        height: f32,
        samples: u32,
    ) -> Self {
        assert!(width > 0.);
        assert!(height > 0.);
        assert!(samples > 0);

        let format = format
            .into()
            .map(|x| x.into())
            .unwrap_or(gfx.surface_format);

        ScreenImage {
            image: Self::create(gfx, format, (width, height), samples),
            format,
            size: (width, height),
            samples,
        }
    }

    /// Returns the inner [Image], also recreating it if the framebuffer has been resized.
    pub fn image(&mut self, gfx: &GraphicsContext) -> Image {
        if Self::size(gfx, self.size) != (self.image.width(), self.image.height()) {
            self.image = Self::create(gfx, self.format, self.size, self.samples);
        }
        self.image.clone()
    }

    fn size(gfx: &GraphicsContext, (width, height): (f32, f32)) -> (u32, u32) {
        let size = gfx.window.inner_size();
        let width = (size.width as f32 * width) as u32;
        let height = (size.height as f32 * height) as u32;
        (width, height)
    }

    fn create(
        gfx: &GraphicsContext,
        format: wgpu::TextureFormat,
        size: (f32, f32),
        samples: u32,
    ) -> Image {
        let (width, height) = Self::size(gfx, size);
        Image::new_canvas_image(gfx, format, width, height, samples)
    }
}
<|endoftext|>


<commit_before>
use super::core::vec::Vec;
use super::core::container::Container;

// Needed, but not detected as needed by the compiler
use super::core::option::{Some, None};
use extra::range;

use screen;

// All the keys pressed in this expression
static mut keys_pressed : [u8, ..256] = [0, ..256];
static mut len_keys_pressed : uint = 0;

// Constants stored throughout the program
static mut letters : [f32, ..27] = [0.0, ..27];

// Each part of the expression is either an operator or a number, if we have an
// error the expression is invalid.
enum Oper	{
	Number(f32),
	Operator(u8),
	Error
}

// Associativity of operators
enum Associativity	{
	Left,
	Right,
	No
}

fn power_of(base : f32, exp : i32) -> f32	{
	let mut ret = base;
	if exp > 0	{
		range(0, exp as uint - 1, |_i|	{
			ret *= base;
		});
	}
	else if exp < 0	{
		ret = 1.0;
		range(0, (-exp) as uint, |_i|	{
			ret /= base;
		});
	}
	else	{
		return 1.0;
	}
	return ret;
}

// Add one key to the expression
pub unsafe fn add_key(key : u8)	{
	if len_keys_pressed == 0	{
		// If this is the first key pressed, we need to clear the screen
		screen::clear_screen(0);
		screen::write_string("\n\t\t", 0);
	}

	// Enter means evaluate the expression
	if key != '\n' as u8	{
		if len_keys_pressed < 256	{
			screen::putc(key, 0);
			// If it is a backspace, we should delete a keypress
			if key == 0x08	{
				if len_keys_pressed > 0	{
					len_keys_pressed -= 1;
				}
			} else	{
				keys_pressed[len_keys_pressed] = key;
				len_keys_pressed += 1;
			}
		}
	}
	else	{
		// If enter is pressed we should get the result and reset our expression
		get_result();
		len_keys_pressed = 0;
	}
}

// Get the result of the globally stored expression
pub unsafe fn get_result()	{
	// Parse the expression and get where to place the expression or -1 in
	// num_letter
	// Expression is parsed into a postfix stack
	let (mut res, num_letter) = parse_expression(keys_pressed, len_keys_pressed);
	if num_letter == -1	{
		screen::write_string(" = ERROR", 0);
		return;
	}
	// Stack with all the numbers as they are being evaluated
	let mut nums : Vec<f32> = Vec::with_capacity(20);

	// If it's empty, loop will not happen and we must set it to false, otherwise
	// it is valid by default.
	let mut valid : bool = res.len() != 0;

	while res.len() > 0	{
		// We know that we can pop at least 1 element
		let tmp = res.pop().get();

		match tmp	{
			Operator(o) =>	{
				// Try to get two numbers from the stack
				let mut tmp = nums.pop();
				match tmp	{
					None => {valid = false;	break;},
					_ => {}
				}
				let num1 = tmp.get();

				tmp = nums.pop();
				match tmp	{
					None => {valid = false;	break;},
					_ => {}
				}
				let num2 = tmp.get();

				match o as u8 as char	{
					'+' => nums.push(num2 + num1),
					'/' => {
						if num1 == 0 as f32 {
							valid = false; break;
						} else	{
							nums.push(num2 / num1)
						}
					},
					'-' => nums.push(num2 - num1),
					'*' => nums.push(num2 * num1),

					// For modulus, we just convert it to integers
					'%' => {
						if num1 as int == 0	{
							valid = false;	break;
						} else	{
							nums.push((num2 as int % num1 as int) as f32)
						}
					},
					'^' => nums.push(power_of(num2, num1 as i32)),
					_   => {valid = false; break;},
				}
			},
			Number(n) => nums.push(n),
			Error => {valid = false; break;}
		}
	}

	if valid	{
		// The expression is valid and the last number in the stack contains the
		// result
		let result : f32 = nums.pop().get();

		// Store the result in our array
		letters[num_letter] = result;

		// Write result in input box
		screen::write_string(" = ", 0);
		screen::write_float(result, 0);
		screen::putc('\n' as u8, 0);

		// Write saved variable
		screen::clear_screen(num_letter as u8 + 5);
		if num_letter == 26	{
			screen::write_string("ANS", num_letter as u8 + 5);
		} else	{
			screen::putc(num_letter as u8 + 'A' as u8, num_letter as u8 + 5);
		}
		screen::write_string(" = ", num_letter as u8 + 5);
		screen::write_float(result, num_letter as u8 + 5);
	}
	else	{
		// Write error if result is invalid
		screen::write_string(" = ERROR", 0);
	}
}

// Get the precedense of one operator
fn get_prec(op : u8) -> int	{
	match op as char	{
		'+' => 1,
		'-' => 1,
		'*' => 2,
		'%' => 2,
		'/' => 2,
		'^' => 3,
		'(' => 4,
		')' => 4,
		_ => 0,
	}
}

// Get associativity of the operator, for now, it is always Left
fn get_associativity(op : u8) -> Associativity	{
	match op as char	{
		'+' => Left,
		'-' => Left,
		'*' => Left,
		'/' => Left,
		'%' => Left,
		'^' => Left,
		'(' => Left,
		')' => Left,
		_ => No,
	}
}

// Check if character is an operator
fn is_oper(c : char) -> bool	{
	c == '+' || c == '*' || c == '%' || c == '-' || c == '/' || c == '^'
}

// If character is a valid letter that should be replaced by a number
fn is_letter(c : u8) -> bool	{
	c >= 'A' as u8 && c <= 'Z' as u8
}

// Parses the expression and creates a postfix stack of the expression
// the integer returned represent where the final result should be placed or -1
// if there is an error in the expression.
fn parse_expression(s : &[u8], len : uint) -> (Vec<Oper>, int)	{
	// Placeholders for numbers we find
	let mut num : f32 = 0.0;

	// We have found and calculated the value of a number
	let mut num_used : bool = false;

	// Used for parsing floating point numbers
	let mut dot_used : uint = 0;

	// Says that the next should be a number or "("
	let mut last_op : bool = true;

	// If the next number we find should be negative
	let mut next_negative : bool = false;

	// Default is to place result in ANS
	let mut letter_answer : int = 26;

	// Temporary stack with operators
	let mut tmp_stack : Vec<u8> = Vec::with_capacity(20);

	// Return (output) stack in reverse order.
	let mut ret_stack : Vec<Oper> = Vec::with_capacity(20);

	// Where we are in the expression
	let mut i : uint = 0;

	while i < len	{
		if (s[i] >= '0' as u8 && s[i] <= '9' as u8) || (num_used == true &&
		s[i] == '.' as u8 && dot_used == 0)	{
			if s[i] == '.' as u8	{
				dot_used = 10;
			}
			else if dot_used > 0	{
				num += ((s[i] as u8 - '0' as u8) as f32) / dot_used as f32;
				dot_used *= 10;
			}
			else	{
				num *= 10.0;
				num += (s[i] as u8 - '0' as u8) as f32;
			}
			num_used = true;
			i += 1;
			continue;
		}
		if num_used == true	{
			// Numbers are only allowed at the beginning or after an operator
			if last_op == false	{
				return (ret_stack, -1);
			}
			if next_negative == true	{
				ret_stack.push(Number(-num));
				next_negative = false;
			}
			else	{
				ret_stack.push(Number(num));
			}
			num = 0.0;
			dot_used = 0;
			num_used = false;
			last_op = false;
		}

		if s[i] == '(' as u8	{
			// Should only have '(' in the beginning or after an operator
			if last_op == false	{
				return (ret_stack, -1);
			}
			tmp_stack.push(s[i]);
		}
		else if s[i] == ')' as u8	{
			// This must be preceeded by a number
			if last_op == true	{
				return (ret_stack, -1);
			}
			last_op = false;
			let mut tmp : u8 = tmp_stack.pop().get();
			while tmp != '(' as u8	{
				ret_stack.push(Operator(tmp));
				tmp = tmp_stack.pop().get();
			}
		}
		else if is_letter(s[i])	{
			// Letter that should be replaced by a number
			let mut j = i+1;
			let mut ans_used = false;

			// Check if the "letter" is "ANS"
			if i+2 < len && s[i+1] == 'N' as u8 && s[i+2] == 'S' as u8	{
				j = i+3;
				ans_used = true;
			}
			// Ignore any spaces
			while j < len && s[j] == ' ' as u8	{
				j += 1;
			}

			// Check if this is where the result value goes or if the letter
			// should be replaced in the expression.
			if s[j] == '=' as u8	{
				if ans_used == false	{
					letter_answer = (s[i] as u8 - 'A' as u8) as int;
					j += 1;	// One extra character to ignore
				}
			}
			else	{
				if ans_used == true	{
					unsafe {num = letters[26]; }
				} else	{
					unsafe {num = letters[s[i] as u8 - 'A' as u8];}
				}
				num_used = true;
			}
			// Increment i and go back to beginning of loop
			i = j;
			continue;
		}
		else if is_oper(s[i] as char)	{
			if last_op == true	{
				if s[i] == '-' as u8 && s[i+1] >= '0' as u8 && s[i+1] <= '9' as u8	{
					next_negative = true;
				}
				else	{
					return (ret_stack, -1);
				}
			}
			else if tmp_stack.len() == 0	{
				tmp_stack.push(s[i]);
				last_op = true;
			}
			else	{
				last_op = true;
				let mut tmp : u8 = tmp_stack.pop().get();
				while tmp_stack.len() > 0 && is_oper(tmp as char) && (get_prec(s[i]) < get_prec(tmp) ||
					(get_prec(s[i]) == get_prec(tmp) && get_associativity(s[i])
					as int == Left as int ) )
				{
					ret_stack.push(Operator(tmp));
					tmp = tmp_stack.pop().get();
				}
				if is_oper(tmp as char) && get_prec(s[i]) <= get_prec(tmp)	{
					ret_stack.push(Operator(tmp));
				}
				else	{
					tmp_stack.push(tmp);
				}
				tmp_stack.push(s[i]);
			}
		}
		else if s[i] != ' ' as u8	{
			// All other characters are invalid
			return (ret_stack, -1);
		}
		i += 1;
	}

	// Need to push the last number
	if num_used == true	{
		if next_negative == true	{
			ret_stack.push(Number(-num));
		} else	{
			ret_stack.push(Number(num));
		}
	}
	// Pop off the rest of the operators
	while tmp_stack.len() > 0	{
		ret_stack.push(Operator(tmp_stack.pop().get() as u8));
	}

	// Need to reverse the stack
	let mut ret : Vec<Oper> = Vec::with_capacity(20);
	while ret_stack.len() > 0	{
		let t = ret_stack.pop().get();
		ret.push(t);

	}
	return (ret, letter_answer);
}

<commit_msg>Changed to not allocate more memory than necessary<commit_after>
use super::core::vec::Vec;
use super::core::container::Container;

// Needed, but not detected as needed by the compiler
use super::core::option::{Some, None};
use extra::range;

use screen;

// All the keys pressed in this expression
static mut keys_pressed : [u8, ..256] = [0, ..256];
static mut len_keys_pressed : uint = 0;

// Constants stored throughout the program
static mut letters : [f32, ..27] = [0.0, ..27];

// Each part of the expression is either an operator or a number, if we have an
// error the expression is invalid.
enum Oper	{
	Number(f32),
	Operator(u8),
	Error
}

// Associativity of operators
enum Associativity	{
	Left,
	Right,
	No
}

fn power_of(base : f32, exp : i32) -> f32	{
	let mut ret = base;
	if exp > 0	{
		range(0, exp as uint - 1, |_i|	{
			ret *= base;
		});
	}
	else if exp < 0	{
		ret = 1.0;
		range(0, (-exp) as uint, |_i|	{
			ret /= base;
		});
	}
	else	{
		return 1.0;
	}
	return ret;
}

// Add one key to the expression
pub unsafe fn add_key(key : u8)	{
	if len_keys_pressed == 0	{
		// If this is the first key pressed, we need to clear the screen
		screen::clear_screen(0);
		screen::write_string("\n\t\t", 0);
	}

	// Enter means evaluate the expression
	if key != '\n' as u8	{
		if len_keys_pressed < 256	{
			screen::putc(key, 0);
			// If it is a backspace, we should delete a keypress
			if key == 0x08	{
				if len_keys_pressed > 0	{
					len_keys_pressed -= 1;
				}
			} else	{
				keys_pressed[len_keys_pressed] = key;
				len_keys_pressed += 1;
			}
		}
	}
	else	{
		// If enter is pressed we should get the result and reset our expression
		get_result();
		len_keys_pressed = 0;
	}
}

// Get the result of the globally stored expression
pub unsafe fn get_result()	{
	// Parse the expression and get where to place the expression or -1 in
	// num_letter
	// Expression is parsed into a postfix stack
	let (mut res, num_letter) = parse_expression(keys_pressed, len_keys_pressed);
	if num_letter == -1	{
		screen::write_string(" = ERROR", 0);
		return;
	}
	// Stack with all the numbers as they are being evaluated, cannot be longer
	// than the length of the result we got
	let mut nums : Vec<f32> = Vec::with_capacity(res.len());

	// If it's empty, loop will not happen and we must set it to false, otherwise
	// it is valid by default.
	let mut valid : bool = res.len() != 0;

	while res.len() > 0	{
		// We know that we can pop at least 1 element
		let tmp = res.pop().get();

		match tmp	{
			Operator(o) =>	{
				// Try to get two numbers from the stack
				let mut tmp = nums.pop();
				match tmp	{
					None => {valid = false;	break;},
					_ => {}
				}
				let num1 = tmp.get();

				tmp = nums.pop();
				match tmp	{
					None => {valid = false;	break;},
					_ => {}
				}
				let num2 = tmp.get();

				match o as u8 as char	{
					'+' => nums.push(num2 + num1),
					'/' => {
						if num1 == 0 as f32 {
							valid = false; break;
						} else	{
							nums.push(num2 / num1)
						}
					},
					'-' => nums.push(num2 - num1),
					'*' => nums.push(num2 * num1),

					// For modulus, we just convert it to integers
					'%' => {
						if num1 as int == 0	{
							valid = false;	break;
						} else	{
							nums.push((num2 as int % num1 as int) as f32)
						}
					},
					'^' => nums.push(power_of(num2, num1 as i32)),
					_   => {valid = false; break;},
				}
			},
			Number(n) => nums.push(n),
			Error => {valid = false; break;}
		}
	}

	if valid	{
		// The expression is valid and the last number in the stack contains the
		// result
		let result : f32 = nums.pop().get();

		// Store the result in our array
		letters[num_letter] = result;

		// Write result in input box
		screen::write_string(" = ", 0);
		screen::write_float(result, 0);
		screen::putc('\n' as u8, 0);

		// Write saved variable
		screen::clear_screen(num_letter as u8 + 5);
		if num_letter == 26	{
			screen::write_string("ANS", num_letter as u8 + 5);
		} else	{
			screen::putc(num_letter as u8 + 'A' as u8, num_letter as u8 + 5);
		}
		screen::write_string(" = ", num_letter as u8 + 5);
		screen::write_float(result, num_letter as u8 + 5);
	}
	else	{
		// Write error if result is invalid
		screen::write_string(" = ERROR", 0);
	}
}

// Get the precedense of one operator
fn get_prec(op : u8) -> int	{
	match op as char	{
		'+' => 1,
		'-' => 1,
		'*' => 2,
		'%' => 2,
		'/' => 2,
		'^' => 3,
		'(' => 4,
		')' => 4,
		_ => 0,
	}
}

// Get associativity of the operator, for now, it is always Left
fn get_associativity(op : u8) -> Associativity	{
	match op as char	{
		'+' => Left,
		'-' => Left,
		'*' => Left,
		'/' => Left,
		'%' => Left,
		'^' => Left,
		'(' => Left,
		')' => Left,
		_ => No,
	}
}

// Check if character is an operator
fn is_oper(c : char) -> bool	{
	c == '+' || c == '*' || c == '%' || c == '-' || c == '/' || c == '^'
}

// If character is a valid letter that should be replaced by a number
fn is_letter(c : u8) -> bool	{
	c >= 'A' as u8 && c <= 'Z' as u8
}

// Parses the expression and creates a postfix stack of the expression
// the integer returned represent where the final result should be placed or -1
// if there is an error in the expression.
fn parse_expression(s : &[u8], len : uint) -> (Vec<Oper>, int)	{
	// Placeholders for numbers we find
	let mut num : f32 = 0.0;

	// We have found and calculated the value of a number
	let mut num_used : bool = false;

	// Used for parsing floating point numbers
	let mut dot_used : uint = 0;

	// Says that the next should be a number or "("
	let mut last_op : bool = true;

	// If the next number we find should be negative
	let mut next_negative : bool = false;

	// Default is to place result in ANS
	let mut letter_answer : int = 26;

	// Temporary stack with operators
	let mut tmp_stack : Vec<u8> = Vec::new();

	// Return (output) stack in reverse order.
	let mut ret_stack : Vec<Oper> = Vec::new();

	// Where we are in the expression
	let mut i : uint = 0;

	while i < len	{
		if (s[i] >= '0' as u8 && s[i] <= '9' as u8) || (num_used == true &&
		s[i] == '.' as u8 && dot_used == 0)	{
			if s[i] == '.' as u8	{
				dot_used = 10;
			}
			else if dot_used > 0	{
				num += ((s[i] as u8 - '0' as u8) as f32) / dot_used as f32;
				dot_used *= 10;
			}
			else	{
				num *= 10.0;
				num += (s[i] as u8 - '0' as u8) as f32;
			}
			num_used = true;
			i += 1;
			continue;
		}
		if num_used == true	{
			// Numbers are only allowed at the beginning or after an operator
			if last_op == false	{
				return (ret_stack, -1);
			}
			if next_negative == true	{
				ret_stack.push(Number(-num));
				next_negative = false;
			}
			else	{
				ret_stack.push(Number(num));
			}
			num = 0.0;
			dot_used = 0;
			num_used = false;
			last_op = false;
		}

		if s[i] == '(' as u8	{
			// Should only have '(' in the beginning or after an operator
			if last_op == false	{
				return (ret_stack, -1);
			}
			tmp_stack.push(s[i]);
		}
		else if s[i] == ')' as u8	{
			// This must be preceeded by a number
			if last_op == true	{
				return (ret_stack, -1);
			}
			last_op = false;
			let mut tmp : u8 = tmp_stack.pop().get();
			while tmp != '(' as u8	{
				ret_stack.push(Operator(tmp));
				tmp = tmp_stack.pop().get();
			}
		}
		else if is_letter(s[i])	{
			// Letter that should be replaced by a number
			let mut j = i+1;
			let mut ans_used = false;

			// Check if the "letter" is "ANS"
			if i+2 < len && s[i+1] == 'N' as u8 && s[i+2] == 'S' as u8	{
				j = i+3;
				ans_used = true;
			}
			// Ignore any spaces
			while j < len && s[j] == ' ' as u8	{
				j += 1;
			}

			// Check if this is where the result value goes or if the letter
			// should be replaced in the expression.
			if s[j] == '=' as u8	{
				if ans_used == false	{
					letter_answer = (s[i] as u8 - 'A' as u8) as int;
					j += 1;	// One extra character to ignore
				}
			}
			else	{
				if ans_used == true	{
					unsafe {num = letters[26]; }
				} else	{
					unsafe {num = letters[s[i] as u8 - 'A' as u8];}
				}
				num_used = true;
			}
			// Increment i and go back to beginning of loop
			i = j;
			continue;
		}
		else if is_oper(s[i] as char)	{
			if last_op == true	{
				if s[i] == '-' as u8 && s[i+1] >= '0' as u8 && s[i+1] <= '9' as u8	{
					next_negative = true;
				}
				else	{
					return (ret_stack, -1);
				}
			}
			else if tmp_stack.len() == 0	{
				tmp_stack.push(s[i]);
				last_op = true;
			}
			else	{
				last_op = true;
				let mut tmp : u8 = tmp_stack.pop().get();
				while tmp_stack.len() > 0 && is_oper(tmp as char) && (get_prec(s[i]) < get_prec(tmp) ||
					(get_prec(s[i]) == get_prec(tmp) && get_associativity(s[i])
					as int == Left as int ) )
				{
					ret_stack.push(Operator(tmp));
					tmp = tmp_stack.pop().get();
				}
				if is_oper(tmp as char) && get_prec(s[i]) <= get_prec(tmp)	{
					ret_stack.push(Operator(tmp));
				}
				else	{
					tmp_stack.push(tmp);
				}
				tmp_stack.push(s[i]);
			}
		}
		else if s[i] != ' ' as u8	{
			// All other characters are invalid
			return (ret_stack, -1);
		}
		i += 1;
	}

	// Need to push the last number
	if num_used == true	{
		if next_negative == true	{
			ret_stack.push(Number(-num));
		} else	{
			ret_stack.push(Number(num));
		}
	}
	// Pop off the rest of the operators
	while tmp_stack.len() > 0	{
		ret_stack.push(Operator(tmp_stack.pop().get() as u8));
	}

	// Need to reverse the stack
	let mut ret : Vec<Oper> = Vec::with_capacity(ret_stack.len());
	while ret_stack.len() > 0	{
		let t = ret_stack.pop().get();
		ret.push(t);

	}
	return (ret, letter_answer);
}

<|endoftext|>


<commit_before>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    if !cfg.is_null() {
        let _ = Box::from_raw(cfg);
    }
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    if !ctx.is_null() {
        let _ = Box::from_raw(ctx);
    }
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    if !frame.is_null() {
        let _ = Box::from_raw(frame);
    }
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
///
/// Returns:
/// - `0` on success,
/// - `> 0` if the input queue is full
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                EnoughData => 1,
                NeedMoreData | NeedMoreFrames => unreachable!(),
                _ => -1,
            }
        })
}

/// Receive encoded data
///
/// Returns:
/// - `0` on success
/// - `> 0` if additional frame data is required
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let rav1e::Packet { data, number, frame_type, .. } = p;
            let len  = data.len();
            let data = Box::into_raw(data.into_boxed_slice()) as *const u8;
            let packet = Packet {
                data,
                len,
                number,
                frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                NeedMoreData |
                    NeedMoreFrames => 1,
                EnoughData => unreachable!(),
                _ => -1,
            }
        })
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    if !pkt.is_null() {
        let pkt = Box::from_raw(pkt);
        let _ = Box::from_raw(pkt.data as *mut u8);
    }
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    if !sequence.is_null() {
        let _ = Box::from_raw(sequence);
    }
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<commit_msg>crav1e: lib: Import option key parsing from rav1e<commit_after>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    if !cfg.is_null() {
        let _ = Box::from_raw(cfg);
    }
}

unsafe fn option_match(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char
) -> Result<(), ()> {
    let key = CStr::from_ptr(key).to_str().map_err(|_| ())?;
    let value = CStr::from_ptr(value).to_str().map_err(|_| ())?;
    let enc = &mut(*cfg).cfg.enc;

    match key {
        "width" => enc.width = value.parse().map_err(|_| ())?,
        "height" => enc.height = value.parse().map_err(|_| ())?,
        "speed" => enc.speed_settings = rav1e::SpeedSettings::from_preset(value.parse().map_err(|_| ())?),

        "threads" => (*cfg).cfg.threads = value.parse().map_err(|_| ())?,

        "tune" => enc.tune = value.parse().map_err(|_| ())?,
        "quantizer" => enc.quantizer = value.parse().map_err(|_| ())?,

        "key_frame_interval" => enc.max_key_frame_interval = value.parse().map_err(|_| ())?,
        "min_key_frame_interval" => enc.min_key_frame_interval = value.parse().map_err(|_| ())?,
        "low_latency" => enc.low_latency = value.parse().map_err(|_| ())?,

        _ => return Err(())
    }

    Ok(())
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Return a negative value on error or 0.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    if option_match(cfg, key, value) == Ok(()) { 0 } else { -1 }
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    if !ctx.is_null() {
        let _ = Box::from_raw(ctx);
    }
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    if !frame.is_null() {
        let _ = Box::from_raw(frame);
    }
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
///
/// Returns:
/// - `0` on success,
/// - `> 0` if the input queue is full
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                EnoughData => 1,
                NeedMoreData | NeedMoreFrames => unreachable!(),
                _ => -1,
            }
        })
}

/// Receive encoded data
///
/// Returns:
/// - `0` on success
/// - `> 0` if additional frame data is required
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let rav1e::Packet { data, number, frame_type, .. } = p;
            let len  = data.len();
            let data = Box::into_raw(data.into_boxed_slice()) as *const u8;
            let packet = Packet {
                data,
                len,
                number,
                frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                NeedMoreData |
                    NeedMoreFrames => 1,
                EnoughData => unreachable!(),
                _ => -1,
            }
        })
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    if !pkt.is_null() {
        let pkt = Box::from_raw(pkt);
        let _ = Box::from_raw(pkt.data as *mut u8);
    }
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    if !sequence.is_null() {
        let _ = Box::from_raw(sequence);
    }
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<|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 bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
use std::process::Command;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint{es_cnx_string: url}.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    // Call status
    let resp = iron_test::request::get("http://localhost:3000/status",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body, r#"{"version":"1.0.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = iron_test::request::get("http://localhost:3000/autocomplete?q=15 Rue Hector Malot, (Paris)",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"Autocomplete":{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot, (Paris)","#,
                         r#""name":"15 Rue Hector Malot, (Paris)","housenumber":"15","#,
                         r#""street":"Rue Hector Malot, (Paris)","postcode":null,"#,
                         r#""city":null}}}]}}"#);
    assert_eq!(result_body, result);
}
<commit_msg>correction test<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 bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
use std::process::Command;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint{es_cnx_string: url}.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    // Call status
    let resp = iron_test::request::get("http://localhost:3000/status",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body, r#"{"version":"1.0.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = iron_test::request::get("http://localhost:3000/autocomplete?q=15 Rue Hector Malot, (Paris)",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"Autocomplete":{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot, (Paris)","#,
                         r#""name":"15 Rue Hector Malot, (Paris)","housenumber":"15","#,
                         r#""street":"Rue Hector Malot, (Paris)","postcode":null,"#,
                         r#""city":null,"administrative_regions":[]}}}]}}"#);
    assert_eq!(result_body, result);
}
<|endoftext|>