<commit_before>use std::io::{Read, Seek, SeekFrom};

use Result;

#[doc(hidden)]
pub trait Band: Read + Seek + Sized {
    #[inline]
    fn jump(&mut self, position: u64) -> Result<u64> {
        self.seek(SeekFrom::Start(position))
    }

    #[inline]
    fn peek<T: Value>(&mut self) -> Result<T> {
        self.stay(|band| Value::read(band))
    }

    #[inline]
    fn position(&mut self) -> Result<u64> {
        self.seek(SeekFrom::Current(0))
    }

    fn stay<F, T>(&mut self, mut body: F) -> Result<T> where F: FnMut(&mut Self) -> Result<T> {
        let position = try!(self.position());
        let result = body(self);
        try!(self.jump(position));
        Ok(try!(result))
    }
}

#[doc(hidden)]
pub trait Value {
    fn read<T: Band>(&mut T) -> Result<Self>;
}

impl<T: Read + Seek> Band for T {
}
<commit_msg>Require Sized for Value<commit_after>use std::io::{Read, Seek, SeekFrom};

use Result;

#[doc(hidden)]
pub trait Band: Read + Seek + Sized {
    #[inline]
    fn jump(&mut self, position: u64) -> Result<u64> {
        self.seek(SeekFrom::Start(position))
    }

    #[inline]
    fn peek<T: Value>(&mut self) -> Result<T> {
        self.stay(|band| Value::read(band))
    }

    #[inline]
    fn position(&mut self) -> Result<u64> {
        self.seek(SeekFrom::Current(0))
    }

    fn stay<F, T>(&mut self, mut body: F) -> Result<T> where F: FnMut(&mut Self) -> Result<T> {
        let position = try!(self.position());
        let result = body(self);
        try!(self.jump(position));
        Ok(try!(result))
    }
}

#[doc(hidden)]
pub trait Value: Sized {
    fn read<T: Band>(&mut T) -> Result<Self>;
}

impl<T: Read + Seek> Band for T {
}
<|endoftext|>


<commit_before>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
//! be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
//! nicely with other types that build on these (such as `std::io::BufReader` and
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
//! an example.)
//!
//! ## Example
//!
//! ```rust
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//!
//! use rusqlite::{Connection, DatabaseName};
//! use std::io::{Read, Write, Seek, SeekFrom};
//!
//! fn main() {
//!     let db = Connection::open_in_memory().unwrap();
//!     db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the BLOB.
//!     let bytes_written = blob.write(b"01234567").unwrap();
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0)).unwrap();
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..]).unwrap();
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap();
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid).unwrap();
//!
//!     assert_eq!(blob.size(), 64);
//! }
//! ```
use std::io;
use std::cmp::min;
use std::mem;
use std::ptr;

use super::ffi;
use {Result, Connection, DatabaseName};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
    /// or if the underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed when the
    /// `Blob` is dropped), but it is available so you can get any errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of the blob
    /// has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of the blob
    /// has been reached.
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase
    /// the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'conn> io::Seek for Blob<'conn> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => self.pos as i64 + offset,
            io::SeekFrom::End(offset) => self.size() as i64 + offset,
        };

        if pos < 0 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to negative position"))
        } else if pos > self.size() as i64 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to position past end of blob"))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};
    use {Connection, DatabaseName, Result};

    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = try!(Connection::open_in_memory());
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        try!(db.execute_batch(sql));
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap());         // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<commit_msg>Add unit test confirming write_all to a Blob fails if given too much data.<commit_after>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
//! be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
//! nicely with other types that build on these (such as `std::io::BufReader` and
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
//! an example.)
//!
//! ## Example
//!
//! ```rust
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//!
//! use rusqlite::{Connection, DatabaseName};
//! use std::io::{Read, Write, Seek, SeekFrom};
//!
//! fn main() {
//!     let db = Connection::open_in_memory().unwrap();
//!     db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the BLOB.
//!     let bytes_written = blob.write(b"01234567").unwrap();
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0)).unwrap();
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..]).unwrap();
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap();
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid).unwrap();
//!
//!     assert_eq!(blob.size(), 64);
//! }
//! ```
use std::io;
use std::cmp::min;
use std::mem;
use std::ptr;

use super::ffi;
use {Result, Connection, DatabaseName};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
    /// or if the underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed when the
    /// `Blob` is dropped), but it is available so you can get any errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of the blob
    /// has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of the blob
    /// has been reached.
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase
    /// the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'conn> io::Seek for Blob<'conn> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => self.pos as i64 + offset,
            io::SeekFrom::End(offset) => self.size() as i64 + offset,
        };

        if pos < 0 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to negative position"))
        } else if pos > self.size() as i64 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to position past end of blob"))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};
    use {Connection, DatabaseName, Result};

    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = try!(Connection::open_in_memory());
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        try!(db.execute_batch(sql));
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap());         // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());

        // write_all should detect when we return Ok(0) because there is no space left,
        // and return a write error
        blob.reopen(rowid).unwrap();
        assert!(blob.write_all(b"0123456789x").is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<|endoftext|>


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

//! Implementation of cross-process surfaces for Android. This uses EGL surface.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::gl2::{egl_image_target_texture2d_oes, TEXTURE_2D, glTexImage2D, BGRA, UNSIGNED_BYTE};
use egl::egl::EGLDisplay;
use egl::eglext::{EGLImageKHR, DestroyImageKHR};
use libc::c_void;
use std::cast;
use std::mem;
use std::ptr;
use std::slice;

/// FIXME(Aydin Kim) :Currently, native surface is consist of 2 types of hybrid image buffer. EGLImageKHR is used to GPU rendering and vector is used to CPU rendering. EGL extension seems not provide simple way to accessing its bitmap directly. In the future, we need to find out the way to integrate them.

pub struct NativeGraphicsMetadata {
    pub display: EGLDisplay,
}

pub struct NativePaintingGraphicsContext{
    display : EGLDisplay,
}

impl NativePaintingGraphicsContext {
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        NativePaintingGraphicsContext {
            display : metadata.display,
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    fn drop(&mut self) {}
}

pub struct NativeCompositingGraphicsContext {
    contents: (),
}

impl NativeCompositingGraphicsContext {
    pub fn new() -> NativeCompositingGraphicsContext {
        NativeCompositingGraphicsContext {
            contents: (),
        }
    }
}

pub struct NativeSurface {
    image: Option<EGLImageKHR>,
    bitmap: *c_void,
    will_leak: bool,
}

impl NativeSurface {
    pub fn from_image_khr(image_khr: EGLImageKHR) -> NativeSurface {
        let mut _image: Option<EGLImageKHR> = None;
        if image_khr != ptr::null() {
            _image = Some(image_khr);
        }
        NativeSurface {
            image : _image,
            bitmap : ptr::null(),
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    /// This may only be called on the case of CPU rendering.
    fn new(_native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, _stride: i32) -> NativeSurface {
        unsafe {
            let len = size.width * size.height * 4;
            let bitmap = slice::from_elem::<u8>(len as uint, 0);

            NativeSurface {
                image: None,
                bitmap: cast::transmute(bitmap),
                will_leak : true,
            }
        }
    }

    /// This may only be called on the compositor side.
    fn bind_to_texture(&self,
                       _native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        let _bound = texture.bind();

        unsafe {
            match self.image {
                None => {
                    if self.bitmap != ptr::null() {
                        glTexImage2D(TEXTURE_2D, 0, BGRA as i32, _size.width as i32, _size.height as i32, 0, BGRA as u32, UNSIGNED_BYTE, self.bitmap);
                    }
                    else {
                        debug!("Cannot bind the buffer(CPU rendering), there is no bitmap");
                    }
                },
                Some(image_khr) => {
                    egl_image_target_texture2d_oes(TEXTURE_2D, image_khr);
                }
            }
        }
    }

    /// This may only be called on the painting side.
    fn upload(&self, _graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            if self.bitmap != ptr::null() {
                let dest:&mut [u8] = cast::transmute((self.bitmap, data.len()));
                dest.copy_memory(data);
            }
            else {
                debug!("Cannot upload the buffer(CPU rendering), there is no bitmap");
            }
        }
    }

    fn get_id(&self) -> int {
        match self.image {
            None => 0,
            Some(image_khr) => image_khr as int,
        }
    }

    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        match self.image {
            None => {},
            Some(image_khr) => {
                DestroyImageKHR(graphics_context.display, image_khr);
                mem::replace(&mut self.image, None);
            }
        }
        self.mark_wont_leak()
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }
    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}
<commit_msg>Android Rust Upgrade fixes<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of cross-process surfaces for Android. This uses EGL surface.

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

use geom::size::Size2D;
use opengles::gl2::{egl_image_target_texture2d_oes, TEXTURE_2D, glTexImage2D, BGRA, UNSIGNED_BYTE};
use egl::egl::EGLDisplay;
use egl::eglext::{EGLImageKHR, DestroyImageKHR};
use libc::c_void;
use std::cast;
use std::mem;
use std::ptr;
use std::vec::Vec;

/// FIXME(Aydin Kim) :Currently, native surface is consist of 2 types of hybrid image buffer. EGLImageKHR is used to GPU rendering and vector is used to CPU rendering. EGL extension seems not provide simple way to accessing its bitmap directly. In the future, we need to find out the way to integrate them.

pub struct NativeGraphicsMetadata {
    pub display: EGLDisplay,
}

pub struct NativePaintingGraphicsContext{
    display : EGLDisplay,
}

impl NativePaintingGraphicsContext {
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        NativePaintingGraphicsContext {
            display : metadata.display,
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    fn drop(&mut self) {}
}

pub struct NativeCompositingGraphicsContext {
    contents: (),
}

impl NativeCompositingGraphicsContext {
    pub fn new() -> NativeCompositingGraphicsContext {
        NativeCompositingGraphicsContext {
            contents: (),
        }
    }
}

pub struct NativeSurface {
    image: Option<EGLImageKHR>,
    bitmap: *c_void,
    will_leak: bool,
}

impl NativeSurface {
    pub fn from_image_khr(image_khr: EGLImageKHR) -> NativeSurface {
        let mut _image: Option<EGLImageKHR> = None;
        if image_khr != ptr::null() {
            _image = Some(image_khr);
        }
        NativeSurface {
            image : _image,
            bitmap : ptr::null(),
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    /// This may only be called on the case of CPU rendering.
    fn new(_native_context: &NativePaintingGraphicsContext, size: Size2D<i32>, _stride: i32) -> NativeSurface {
        unsafe {
            let len = size.width * size.height * 4;
            let bitmap: Vec<u8> = Vec::from_elem(len as uint, 0 as u8);

            NativeSurface {
                image: None,
                bitmap: cast::transmute(bitmap.as_ptr()),
                will_leak : true,
            }
        }
    }

    /// This may only be called on the compositor side.
    fn bind_to_texture(&self,
                       _native_context: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       _size: Size2D<int>) {
        let _bound = texture.bind();

        unsafe {
            match self.image {
                None => {
                    if self.bitmap != ptr::null() {
                        glTexImage2D(TEXTURE_2D, 0, BGRA as i32, _size.width as i32, _size.height as i32, 0, BGRA as u32, UNSIGNED_BYTE, self.bitmap);
                    }
                    else {
                        debug!("Cannot bind the buffer(CPU rendering), there is no bitmap");
                    }
                },
                Some(image_khr) => {
                    egl_image_target_texture2d_oes(TEXTURE_2D, image_khr);
                }
            }
        }
    }

    /// This may only be called on the painting side.
    fn upload(&self, _graphics_context: &NativePaintingGraphicsContext, data: &[u8]) {
        unsafe {
            if self.bitmap != ptr::null() {
                let dest:&mut [u8] = cast::transmute((self.bitmap, data.len()));
                dest.copy_memory(data);
            }
            else {
                debug!("Cannot upload the buffer(CPU rendering), there is no bitmap");
            }
        }
    }

    fn get_id(&self) -> int {
        match self.image {
            None => 0,
            Some(image_khr) => image_khr as int,
        }
    }

    fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        match self.image {
            None => {},
            Some(image_khr) => {
                DestroyImageKHR(graphics_context.display, image_khr);
                mem::replace(&mut self.image, None);
            }
        }
        self.mark_wont_leak()
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }
    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}
<|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) {
    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) {
    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) {
    let _ = Arc::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 packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.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) {
    let _ = Box::from_raw(pkt);
}

/// 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) {
    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: rav1e_frame_unref: Use Box instead of Arc<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) {
    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) {
    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) {
    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 packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.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) {
    let _ = Box::from_raw(pkt);
}

/// 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) {
    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>#![allow(dead_code)]

pub enum Orientation {
    Across,
    Down
}

pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }
}

pub const BARRIER: char = '█';

pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    fn write(&mut self, row_index: usize, col_index: usize,
             letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    #[allow(unused_variables)]
    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        // TODO
    }

}

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

    fn test_puzzle() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    #[test]
    fn test_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle().read_wordspan(write_address),
                   vec!['W', 'R', 'I', 'T', 'E']);
    }

    #[test]
    fn test_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle().read_wordspan(raise_address),
                   vec!['R', 'A', 'I', 'S', 'E']);
    }

}
<commit_msg>write wordspans; standard derivations<commit_after>#![allow(dead_code)]

#[derive(Clone, Copy, Debug)]
pub enum Orientation {
    Across,
    Down
}

#[derive(Clone, Copy, Debug)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    fn write(&mut self, row_index: usize, col_index: usize,
             letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

}

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

    fn test_puzzle() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle().read_wordspan(write_address),
                   vec!['W', 'R', 'I', 'T', 'E']);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle().read_wordspan(raise_address),
                   vec!['R', 'A', 'I', 'S', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, vec!['P', 'L', 'A', 'T', 'E']);
        assert_eq!(puzzle.read_wordspan(write_address),
                   vec!['P', 'L', 'A', 'T', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, vec!['F', 'A', 'I', 'T', 'H']);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   vec!['F', 'A', 'I', 'T', 'H']);
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate abomonation_derive;
extern crate abomonation;

extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::ProbeHandle;
// use timely::progress::timestamp::RootTimestamp;

use timely::dataflow::operators::unordered_input::UnorderedInput;

use differential_dataflow::AsCollection;
use differential_dataflow::operators::*;

use pair::Pair;

fn main() {

    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();
    let batch: usize = std::env::args().nth(3).unwrap().parse().unwrap();
    let rounds: usize = std::env::args().nth(4).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(5), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let mut probe = ProbeHandle::new();

        let (mut root_input, root_cap, mut edge_input, mut edge_cap) =
        worker.dataflow(|scope| {

            let ((root_input, root_cap), roots) = scope.new_unordered_input();
            let ((edge_input, edge_cap), edges) = scope.new_unordered_input();

            let roots = roots.as_collection();
            let edges = edges.as_collection()
                             // .inspect(|x| println!("edge: {:?}", x))
                             ;

            roots.iterate(|inner| {

                let edges = edges.enter(&inner.scope());
                let roots = roots.enter(&inner.scope());

                edges
                    .semijoin(&inner)
                    .map(|(_s,d)| d)
                    .concat(&roots)
                    .distinct()
            })
            .consolidate()
            // .inspect(|x| println!("edge: {:?}", x))
            .map(|_| ())
            .consolidate()
            .inspect(|x| println!("{:?}\tchanges: {:?}", x.1, x.2))
            .probe_with(&mut probe);

            (root_input, root_cap, edge_input, edge_cap)
        });

        let seed: &[_] = &[1, 2, 3, index];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        let mut rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions

        let worker_edges = edges / peers + if index < edges % peers { 1 } else { 0 };
        let worker_batch = batch / peers + if index < batch % peers { 1 } else { 0 };

        // Times: (revision, event_time)

        // load initial root.
        root_input
            .session(root_cap)
            .give((0, Pair::new(0, 0), 1));

        // load initial edges
        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_edges).map(|_|
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)),
                    Pair::new(0, 0), 1)
            ));

        let edge_cap_next = edge_cap.delayed(&Pair::new(1, 0));

        // Caps = { (1,0) , (0,1) }

        edge_cap.downgrade(&Pair::new(0, 1));
        while probe.less_than(edge_cap.time()) {
            worker.step();
        }

        println!("Initial computation complete");

        for round in 1 .. rounds {

            edge_input
                .session(edge_cap.clone())
                .give_iterator((0 .. worker_batch).flat_map(|_| {
                    let insert = ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(0, round), 1);
                    let remove = ((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)), Pair::new(0, round),-1);
                    Some(insert).into_iter().chain(Some(remove).into_iter())
                }));

            edge_cap.downgrade(&Pair::new(0, round+1));
            while probe.less_than(edge_cap.time()) {
                worker.step();
            }

            // Caps = { (1,0), (0,round+1) }
            println!("Initial round {} complete", round);
        }

        // Caps = { (1,0) }
        let edge_cap0 = edge_cap;
        println!("{:?}", edge_cap0);
        edge_cap = edge_cap_next;

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(1, 0), 1)
            }));

        // Caps = { (2,0) }
        edge_cap.downgrade(&Pair::new(2, 0));
        while probe.less_equal(&Pair::new(1, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(2, 3), 1)
            }));

        // Caps = { (3,0) }
        edge_cap.downgrade(&Pair::new(3, 0));
        while probe.less_equal(&Pair::new(2, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(3, 1), 1)
            }));

        // Caps = { (4,0) }
        edge_cap.downgrade(&Pair::new(4, 0));
        while probe.less_equal(&Pair::new(3, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap0)
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(0, 10), 1)
            }));

    }).unwrap();
}

/// This module contains a definition of a new timestamp time, a "pair" or product.
///
/// This is a minimal self-contained implementation, in that it doesn't borrow anything
/// from the rest of the library other than the traits it needs to implement. With this
/// type and its implementations, you can use it as a timestamp type.
mod pair {

    /// A pair of timestamps, partially ordered by the product order.
    #[derive(Hash, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Abomonation)]
    pub struct Pair<S, T> {
        pub first: S,
        pub second: T,
    }

    impl<S, T> Pair<S, T> {
        /// Create a new pair.
        pub fn new(first: S, second: T) -> Self {
            Pair { first, second }
        }
    }

    // Implement timely dataflow's `PartialOrder` trait.
    use timely::order::PartialOrder;
    impl<S: PartialOrder, T: PartialOrder> PartialOrder for Pair<S, T> {
        fn less_equal(&self, other: &Self) -> bool {
            self.first.less_equal(&other.first) && self.second.less_equal(&other.second)
        }
    }

    use timely::progress::timestamp::Refines;
    impl<S: Timestamp, T: Timestamp> Refines<()> for Pair<S, T> {
        fn to_inner(_outer: ()) -> Self { Default::default() }
        fn to_outer(self) -> () { () }
        fn summarize(_summary: <Self>::Summary) -> () { () }
    }

    // Implement timely dataflow's `PathSummary` trait.
    // This is preparation for the `Timestamp` implementation below.
    use timely::progress::PathSummary;
    // impl<S: Timestamp, T: Timestamp> PathSummary<Pair<S,T>> for Pair<<S as Timestamp>::Summary, <T as Timestamp>::Summary> {
    //     fn results_in(&self, timestamp: &Pair<S, T>) -> Option<Pair<S,T>> {
    //         if let Some(s) = self.first.results_in(&timestamp.first) {
    //             if let Some(t) = self.second.results_in(&timestamp.second) {
    //                 Some(Pair::new(s,t))
    //             }
    //             else { None }
    //         }
    //         else { None }
    //     }
    //     fn followed_by(&self, other: &Self) -> Option<Self> {
    //         if let Some(s) = self.first.followed_by(&other.first) {
    //             if let Some(t) = self.second.followed_by(&other.second) {
    //                 Some(Pair::new(s,t))
    //             }
    //             else { None }
    //         }
    //         else { None }
    //     }
    // }

    impl<S: Timestamp, T: Timestamp> PathSummary<Pair<S,T>> for () {
        fn results_in(&self, timestamp: &Pair<S, T>) -> Option<Pair<S,T>> {
            Some(timestamp.clone())
        }
        fn followed_by(&self, other: &Self) -> Option<Self> {
            Some(other.clone())
        }
    }

    // Implement timely dataflow's `Timestamp` trait.
    use timely::progress::Timestamp;
    impl<S: Timestamp, T: Timestamp> Timestamp for Pair<S, T> {
        type Summary = ();//Pair<<S as Timestamp>::Summary, <T as Timestamp>::Summary>;
    }

    // Implement differential dataflow's `Lattice` trait.
    // This extends the `PartialOrder` implementation with additional structure.
    use differential_dataflow::lattice::Lattice;
    impl<S: Lattice, T: Lattice> Lattice for Pair<S, T> {
        fn minimum() -> Self { Pair { first: S::minimum(), second: T::minimum() }}
        fn maximum() -> Self { Pair { first: S::maximum(), second: T::maximum() }}
        fn join(&self, other: &Self) -> Self {
            Pair {
                first: self.first.join(&other.first),
                second: self.second.join(&other.second),
            }
        }
        fn meet(&self, other: &Self) -> Self {
            Pair {
                first: self.first.meet(&other.first),
                second: self.second.meet(&other.second),
            }
        }
    }

    use std::fmt::{Formatter, Error, Debug};

    /// Debug implementation to avoid seeing fully qualified path names.
    impl<TOuter: Debug, TInner: Debug> Debug for Pair<TOuter, TInner> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("({:?}, {:?})", self.first, self.second))
    }
}

}<commit_msg>correct to track timely changes<commit_after>#[macro_use]
extern crate abomonation_derive;
extern crate abomonation;

extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::ProbeHandle;
// use timely::progress::timestamp::RootTimestamp;

use timely::dataflow::operators::unordered_input::UnorderedInput;

use differential_dataflow::AsCollection;
use differential_dataflow::operators::*;

use pair::Pair;

fn main() {

    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();
    let batch: usize = std::env::args().nth(3).unwrap().parse().unwrap();
    let rounds: usize = std::env::args().nth(4).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(5), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let mut probe = ProbeHandle::new();

        let (mut root_input, root_cap, mut edge_input, mut edge_cap) =
        worker.dataflow(|scope| {

            let ((root_input, root_cap), roots) = scope.new_unordered_input();
            let ((edge_input, edge_cap), edges) = scope.new_unordered_input();

            let roots = roots.as_collection();
            let edges = edges.as_collection()
                             // .inspect(|x| println!("edge: {:?}", x))
                             ;

            roots.iterate(|inner| {

                let edges = edges.enter(&inner.scope());
                let roots = roots.enter(&inner.scope());

                edges
                    .semijoin(&inner)
                    .map(|(_s,d)| d)
                    .concat(&roots)
                    .distinct()
            })
            .consolidate()
            // .inspect(|x| println!("edge: {:?}", x))
            .map(|_| ())
            .consolidate()
            .inspect(|x| println!("{:?}\tchanges: {:?}", x.1, x.2))
            .probe_with(&mut probe);

            (root_input, root_cap, edge_input, edge_cap)
        });

        let seed: &[_] = &[1, 2, 3, index];
        let mut rng1: StdRng = SeedableRng::from_seed(seed);    // rng for edge additions
        let mut rng2: StdRng = SeedableRng::from_seed(seed);    // rng for edge deletions

        let worker_edges = edges / peers + if index < edges % peers { 1 } else { 0 };
        let worker_batch = batch / peers + if index < batch % peers { 1 } else { 0 };

        // Times: (revision, event_time)

        // load initial root.
        root_input
            .session(root_cap)
            .give((0, Pair::new(0, 0), 1));

        // load initial edges
        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_edges).map(|_|
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)),
                    Pair::new(0, 0), 1)
            ));

        let edge_cap_next = edge_cap.delayed(&Pair::new(1, 0));

        // Caps = { (1,0) , (0,1) }

        edge_cap.downgrade(&Pair::new(0, 1));
        while probe.less_than(edge_cap.time()) {
            worker.step();
        }

        println!("Initial computation complete");

        for round in 1 .. rounds {

            edge_input
                .session(edge_cap.clone())
                .give_iterator((0 .. worker_batch).flat_map(|_| {
                    let insert = ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(0, round), 1);
                    let remove = ((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)), Pair::new(0, round),-1);
                    Some(insert).into_iter().chain(Some(remove).into_iter())
                }));

            edge_cap.downgrade(&Pair::new(0, round+1));
            while probe.less_than(edge_cap.time()) {
                worker.step();
            }

            // Caps = { (1,0), (0,round+1) }
            println!("Initial round {} complete", round);
        }

        // Caps = { (1,0) }
        let edge_cap0 = edge_cap;
        println!("{:?}", edge_cap0.time());
        edge_cap = edge_cap_next;

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(1, 0), 1)
            }));

        // Caps = { (2,0) }
        edge_cap.downgrade(&Pair::new(2, 0));
        while probe.less_equal(&Pair::new(1, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(2, 3), 1)
            }));

        // Caps = { (3,0) }
        edge_cap.downgrade(&Pair::new(3, 0));
        while probe.less_equal(&Pair::new(2, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap.clone())
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(3, 1), 1)
            }));

        // Caps = { (4,0) }
        edge_cap.downgrade(&Pair::new(4, 0));
        while probe.less_equal(&Pair::new(3, rounds-1)) {
            worker.step();
        }

        edge_input
            .session(edge_cap0)
            .give_iterator((0 .. worker_batch).map(|_| {
                ((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), Pair::new(0, 10), 1)
            }));

    }).unwrap();
}

/// This module contains a definition of a new timestamp time, a "pair" or product.
///
/// This is a minimal self-contained implementation, in that it doesn't borrow anything
/// from the rest of the library other than the traits it needs to implement. With this
/// type and its implementations, you can use it as a timestamp type.
mod pair {

    /// A pair of timestamps, partially ordered by the product order.
    #[derive(Hash, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Abomonation)]
    pub struct Pair<S, T> {
        pub first: S,
        pub second: T,
    }

    impl<S, T> Pair<S, T> {
        /// Create a new pair.
        pub fn new(first: S, second: T) -> Self {
            Pair { first, second }
        }
    }

    // Implement timely dataflow's `PartialOrder` trait.
    use timely::order::PartialOrder;
    impl<S: PartialOrder, T: PartialOrder> PartialOrder for Pair<S, T> {
        fn less_equal(&self, other: &Self) -> bool {
            self.first.less_equal(&other.first) && self.second.less_equal(&other.second)
        }
    }

    use timely::progress::timestamp::Refines;
    impl<S: Timestamp, T: Timestamp> Refines<()> for Pair<S, T> {
        fn to_inner(_outer: ()) -> Self { Default::default() }
        fn to_outer(self) -> () { () }
        fn summarize(_summary: <Self>::Summary) -> () { () }
    }

    // Implement timely dataflow's `PathSummary` trait.
    // This is preparation for the `Timestamp` implementation below.
    use timely::progress::PathSummary;

    impl<S: Timestamp, T: Timestamp> PathSummary<Pair<S,T>> for () {
        fn results_in(&self, timestamp: &Pair<S, T>) -> Option<Pair<S,T>> {
            Some(timestamp.clone())
        }
        fn followed_by(&self, other: &Self) -> Option<Self> {
            Some(other.clone())
        }
    }

    // Implement timely dataflow's `Timestamp` trait.
    use timely::progress::Timestamp;
    impl<S: Timestamp, T: Timestamp> Timestamp for Pair<S, T> {
        type Summary = ();
    }

    // Implement differential dataflow's `Lattice` trait.
    // This extends the `PartialOrder` implementation with additional structure.
    use differential_dataflow::lattice::Lattice;
    impl<S: Lattice, T: Lattice> Lattice for Pair<S, T> {
        fn minimum() -> Self { Pair { first: S::minimum(), second: T::minimum() }}
        fn maximum() -> Self { Pair { first: S::maximum(), second: T::maximum() }}
        fn join(&self, other: &Self) -> Self {
            Pair {
                first: self.first.join(&other.first),
                second: self.second.join(&other.second),
            }
        }
        fn meet(&self, other: &Self) -> Self {
            Pair {
                first: self.first.meet(&other.first),
                second: self.second.meet(&other.second),
            }
        }
    }

    use std::fmt::{Formatter, Error, Debug};

    /// Debug implementation to avoid seeing fully qualified path names.
    impl<TOuter: Debug, TInner: Debug> Debug for Pair<TOuter, TInner> {
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            f.write_str(&format!("({:?}, {:?})", self.first, self.second))
        }
    }

}<|endoftext|>


<commit_before>use std::os;
use std::str;
use std::fmt;

fn main() {
    let args = os::args();

    if args.len() == 1 {
        fail!("no arguments");
    }

    run(tokenize(parse_args(args)));
}

fn parse_args(args: ~[~str]) -> ~str {
    args[1]
}

fn tokenize(text: ~str) -> Vec<Token> {
    let mut tokens: Vec<Token> = Vec::new();
    for c in text.chars() {
       match c {
           '>' => {tokens.push(Right)},
           '<' => {tokens.push(Left)},
           '+' => {tokens.push(Plus)},
           '-' => {tokens.push(Minus)},
           '.' => {tokens.push(Out)},
           ',' => {tokens.push(In)},
           '[' => {tokens.push(Jump)},
           ']' => {tokens.push(Loop)},
           _ => {}
       };
    }

    return tokens;
}

fn run(tokens: Vec<Token>) {
    let mut data: Vec<u8> = Vec::new();
    let mut jump_stack: Vec<uint> = Vec::new();

    let mut pointer: uint = 0;
    let mut token_index: uint = 0;

    let token_slice = tokens.as_slice();

    data.push(0);

    while token_index < tokens.len() {
        std::io::timer::sleep(10);
        for (i, t) in tokens.iter().enumerate() {
            if i == token_index {
                print!("\x1b[34m{:3}\x1b[0m", t);
            } else {
                print!("{:3}", t);
            }
        }
        print!("\n");

        let token = token_slice[token_index];
        match token {
            Right => {
                pointer += 1;
                if pointer == data.len() {
                    data.push(0);
                }

                token_index += 1;
            },

            Left => {
                if pointer == 0 {
                    fail!("index out of bounds");
                }

                pointer -= 1;
                token_index += 1;
            },

            Plus => {
                *data.get_mut(pointer) += 1;
                token_index += 1;
            },

            Minus => {
                *data.get_mut(pointer) -= 1;
                token_index += 1;
            },

            Out => {
                match  str::from_utf8(data.slice(pointer, pointer + 1)) {
                    Some(c) => {print!("{}", c)},
                    None => {}
                }

                token_index += 1;
            },

            Jump => {

                // Jump to end of the loop when the value at the pointer is zero.
                if *data.get_mut(pointer) == 0 {

                    let mut jump_count = 0;
                    loop {
                        token_index += 1;

                        if token_index > tokens.len() {
                            fail!("no matching ]");
                        }

                        match token_slice[token_index] {
                            Loop => {
                                if jump_count == 0 {
                                    token_index += 1;
                                    break;
                                } else {
                                    jump_count -= 1;
                                }
                            },

                            Jump => {
                                jump_count += 1;
                            },

                            _ => {}
                        }
                    }
                } else {
                    jump_stack.push(token_index);
                    token_index += 1;
                }
            },

            Loop => {
                match jump_stack.pop() {
                    Some(i) => {token_index = i},
                    None => {}
                }
            },

            _ => {}
        }

        print!("{} {} ", token, pointer);
        for (i, d) in data.iter().enumerate() {
            if i == pointer {
                print!("|\x1b[31m{:3}\x1b[0m", d);
            } else {
                print!("|{:3}", d);
            }
        }
        print!("|\n");
    }

    print!("\n");
}

#[deriving(Clone, Eq, TotalEq)]
enum Token {
    Right,
    Left,
    Plus,
    Minus,
    Out,
    In,
    Jump,
    Loop
}

impl fmt::Show for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", match *self {
            Right => '>',
            Left => '<',
            Plus => '+',
            Minus => '-',
            Out => '.',
            In => ',',
            Jump => '[',
            Loop => ']',
        })
    }
}

#[test]
fn testTokenizer() {
    // Check the tokenizer is getting the right outputs.
    assert_eq!(tokenize("><+-.,[]".to_owned()).as_slice(),
               [Right, Left, Plus, Minus, Out, In, Jump, Loop].as_slice());

    // Make sure junk is ignored.
    assert_eq!(tokenize(">a<b+c-d. ,1[2]3 ".to_owned()).as_slice(),
               [Right, Left, Plus, Minus, Out, In, Jump, Loop].as_slice());
}

#[test]
fn testArgParser() {
    assert_eq!(parse_args(["brainruck".to_owned(), "><+-.,[]".to_owned()].to_owned()),
               "><+-.,[]".to_owned());
}
<commit_msg>Remove debug code, add input<commit_after>use std::os;
use std::str;
use std::fmt;

fn main() {
    let args = os::args();

    if args.len() == 1 {
        fail!("no arguments");
    }

    run(tokenize(parse_args(args)));
}

fn parse_args(args: ~[~str]) -> ~str {
    args[1]
}

fn tokenize(text: ~str) -> Vec<Token> {
    let mut tokens: Vec<Token> = Vec::new();
    for c in text.chars() {
       match c {
           '>' => {tokens.push(Right)},
           '<' => {tokens.push(Left)},
           '+' => {tokens.push(Plus)},
           '-' => {tokens.push(Minus)},
           '.' => {tokens.push(Out)},
           ',' => {tokens.push(In)},
           '[' => {tokens.push(Jump)},
           ']' => {tokens.push(Loop)},
           _ => {}
       };
    }

    return tokens;
}

fn run(tokens: Vec<Token>) {
    let mut data: Vec<u8> = Vec::new();
    let mut jump_stack: Vec<uint> = Vec::new();

    let mut pointer: uint = 0;
    let mut token_index: uint = 0;

    let token_slice = tokens.as_slice();

    data.push(0);

    while token_index < tokens.len() {
        let token = token_slice[token_index];
        match token {
            Right => {
                pointer += 1;
                if pointer == data.len() {
                    data.push(0);
                }

                token_index += 1;
            },

            Left => {
                if pointer == 0 {
                    fail!("index out of bounds");
                }

                pointer -= 1;
                token_index += 1;
            },

            Plus => {
                *data.get_mut(pointer) += 1;
                token_index += 1;
            },

            Minus => {
                *data.get_mut(pointer) -= 1;
                token_index += 1;
            },

            Out => {
                match  str::from_utf8(data.slice(pointer, pointer + 1)) {
                    Some(c) => {print!("{}", c)},
                    None => {}
                }

                token_index += 1;
            },

            In => {
                match std::io::stdin().read_byte() {
                    Ok(b) => {*data.get_mut(pointer) = b},
                    Err(e) => {fail!("{}", e)}
                }
                token_index += 1;
            },

            Jump => {

                // Jump to end of the loop when the value at the pointer is zero.
                if *data.get_mut(pointer) == 0 {

                    let mut jump_count = 0;
                    loop {
                        token_index += 1;

                        if token_index > tokens.len() {
                            fail!("no matching ]");
                        }

                        match token_slice[token_index] {
                            Loop => {
                                if jump_count == 0 {
                                    token_index += 1;
                                    break;
                                } else {
                                    jump_count -= 1;
                                }
                            },

                            Jump => {
                                jump_count += 1;
                            },

                            _ => {}
                        }
                    }
                } else {
                    jump_stack.push(token_index);
                    token_index += 1;
                }
            },

            Loop => {
                match jump_stack.pop() {
                    Some(i) => {token_index = i},
                    None => {}
                }
            },
        }
    }

    print!("\n");
}

#[deriving(Clone, Eq, TotalEq)]
enum Token {
    Right,
    Left,
    Plus,
    Minus,
    Out,
    In,
    Jump,
    Loop
}

impl fmt::Show for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", match *self {
            Right => '>',
            Left => '<',
            Plus => '+',
            Minus => '-',
            Out => '.',
            In => ',',
            Jump => '[',
            Loop => ']',
        })
    }
}

#[test]
fn testTokenizer() {
    // Check the tokenizer is getting the right outputs.
    assert_eq!(tokenize("><+-.,[]".to_owned()).as_slice(),
               [Right, Left, Plus, Minus, Out, In, Jump, Loop].as_slice());

    // Make sure junk is ignored.
    assert_eq!(tokenize(">a<b+c-d. ,1[2]3 ".to_owned()).as_slice(),
               [Right, Left, Plus, Minus, Out, In, Jump, Loop].as_slice());
}

#[test]
fn testArgParser() {
    assert_eq!(parse_args(["brainruck".to_owned(), "><+-.,[]".to_owned()].to_owned()),
               "><+-.,[]".to_owned());
}
<|endoftext|>