<commit_before>use std::fs::OpenOptions;
use std::fs;
use std::io::prelude::*;

/// Gets every json from a subdirectory and writes an html file in directory
/// to display the json data as a table, as well as create an index html
/// in directorys parentfolder containing a link to all created json tables
pub fn write_html_from_json(directory: &str, subdirectory: &str) {
    // The full path: dir\\subdir
    let mut full_path = directory.to_string();
    full_path.push_str("\\");
    full_path.push_str(subdirectory);
    // Create index file
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("index.html")
        .unwrap();
    // Start of indexfile html
    let _ = writeln!(file, "");
    // Get all json files
    // dir\\subdir\\<file>.json
    for entry in fs::read_dir(full_path.clone()).unwrap() {
        // Path to the file
        let dir = entry.unwrap();
        // Removes the subdirectory
        // dir\\<file>.json
        let path_parent = dir
            .path()
            .into_os_string()
            .into_string()
            .unwrap()
            .replace(&format!("\\{}", subdirectory), "");
        // dir\\<file>.html
        let path_parent_html = path_parent.clone().replace("json", "html");
        // Create html file <dir>\\<file>.html
        let mut file_parent_html = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(path_parent_html.clone())
        .unwrap();
        // Write to dir\\<file>.html
        let _ = file_parent_html.write_all(

// LARGE HTML AHEAD
"<!DOCTYPE html>

        <meta charset=\"utf-8\"/>
        <link rel=\"stylesheet\" href=\"css/jquery.dynatable.css\">

        back

            Artist
            Title
            Count

        back

"
// END OF MORE HTML

        .as_bytes());
        // link to dir\\<file>.html
        let _ = writeln!(file, "{0}
", path_parent_html);
    }
    let _ = writeln!(file, "");
}
<commit_msg>Skip html generation for non json files<commit_after>use std::fs::OpenOptions;
use std::fs;
use std::io::prelude::*;

/// Gets every json from a subdirectory and writes an html file in directory
/// to display the json data as a table, as well as create an index html
/// in directorys parentfolder containing a link to all created json tables
pub fn write_html_from_json(directory: &str, subdirectory: &str) {
    // The full path: dir\\subdir
    let mut full_path = directory.to_string();
    full_path.push_str("\\");
    full_path.push_str(subdirectory);
    // Create index file
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("index.html")
        .unwrap();
    // Start of indexfile html
    let _ = writeln!(file, "");
    // Get all json files
    // dir\\subdir\\<file>.json
    for entry in fs::read_dir(full_path.clone()).unwrap() {
        // Path to the file
        let dir = entry.unwrap();
        // Removes the subdirectory
        // dir\\<file>.json
        let path_parent = dir
            .path()
            .into_os_string()
            .into_string()
            .unwrap()
            .replace(&format!("\\{}", subdirectory), "");
        if !path_parent.ends_with(".json"){
            continue;
        }
        // dir\\<file>.html
        let path_parent_html = path_parent.clone().replace("json", "html");
        // Create html file <dir>\\<file>.html
        let mut file_parent_html = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(path_parent_html.clone())
        .unwrap();
        // Write to dir\\<file>.html
        let _ = file_parent_html.write_all(

// LARGE HTML AHEAD
"<!DOCTYPE html>

        <meta charset=\"utf-8\"/>
        <link rel=\"stylesheet\" href=\"css/jquery.dynatable.css\">

        back

            Artist
            Title
            Count

        back

"
// END OF MORE HTML

        .as_bytes());
        // link to dir\\<file>.html
        let _ = writeln!(file, "{0}
", path_parent_html);
    }
    let _ = writeln!(file, "");
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use memmap::{Mmap, Protection};
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write};
use std;

// TODO: ...
// pub type Offset(u64);

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

/// An index is a file with pairs of relative offset to file position offset
/// messages. Both are stored as 4 bytes.
pub struct Index {
    file: File,
    mmap: Mmap,

    /// next starting byte in index file offset to write
    next_write_offset: usize,
    base_offset: u64,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IndexEntry {
    rel_offset: u32,
    base_offset: u64,
    file_pos: u32,
}

impl IndexEntry {
    pub fn relative_offset(&self) -> u32 {
        self.rel_offset
    }

    #[inline]
    pub fn offset(&self) -> u64 {
        self.base_offset + (self.rel_offset as u64)
    }

    #[inline]
    pub fn file_position(&self) -> u32 {
        self.file_pos
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IndexWriteError {
    IndexFull,
    OffsetLessThanBase,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IndexReadError {
    OutOfBounds,
}

impl Index {
    pub fn new<P>(path: P, file_bytes: u64, base_offset: u64) -> io::Result<Index>
        where P: AsRef<Path>
    {
        // open the file, expecting to create it
        let index_file = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .append(true)
            .create(true)
            .open(path));

        // read the metadata and truncate
        let meta = try!(index_file.metadata());
        let len = meta.len();
        if len == 0 {
            try!(index_file.set_len(file_bytes));
        }

        let mmap = try!(Mmap::open(&index_file, Protection::ReadWrite));

        Ok(Index {
            file: index_file,
            mmap: mmap,
            next_write_offset: len as usize,
            base_offset: base_offset,
        })
    }

    #[inline]
    pub fn can_write(&self) -> bool {
        self.size() >= (self.next_write_offset + 8)
    }

    #[inline]
    pub fn size(&self) -> usize {
        self.mmap.len()
    }

    pub fn append(&mut self, abs_offset: u64, position: u32) -> Result<(), IndexWriteError> {
        // TODO: test to ensure abs_offset is < last offset written (invariant of the index)
        if !self.can_write() {
            return Err(IndexWriteError::IndexFull);
        }

        if abs_offset < self.base_offset {
            return Err(IndexWriteError::OffsetLessThanBase);
        }

        unsafe {
            let mem_slice: &mut [u8] = self.mmap.as_mut_slice();
            let offset = (abs_offset - self.base_offset) as u32;
            let buf_pos = self.next_write_offset;

            BigEndian::write_u32(&mut mem_slice[buf_pos..buf_pos + 4], offset);
            BigEndian::write_u32(&mut mem_slice[buf_pos + 4..buf_pos + 8], position);

            self.next_write_offset += 8;

            Ok(())
        }
    }

    pub fn flush_sync(&mut self) -> io::Result<()> {
        try!(self.mmap.flush());
        self.file.flush()
    }

    pub fn read_entry(&self, i: usize) -> Result<Option<IndexEntry>, IndexReadError> {
        if self.size() < (i + 1) * 8 {
            return Err(IndexReadError::OutOfBounds);
        }

        unsafe {
            let mem_slice = self.mmap.as_slice();
            let start = i * 8;
            let offset = BigEndian::read_u32(&mem_slice[start..start + 4]);
            if offset == 0 && i > 0 {
                Ok(None)
            } else {
                let pos = BigEndian::read_u32(&mem_slice[start + 4..start + 8]);
                Ok(Some(IndexEntry {
                    rel_offset: offset,
                    base_offset: self.base_offset,
                    file_pos: pos,
                }))
            }
        }
    }
}

pub struct Log {
    f: File,
    max_bytes: usize,
    pos: usize,
}

#[derive(Debug)]
pub enum LogAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<std::io::Error> for LogAppendError {
    #[inline]
    fn from(e: std::io::Error) -> LogAppendError {
        LogAppendError::IoError(e)
    }
}

impl Log {
    pub fn new<P>(p: P, max_bytes: usize) -> io::Result<Log>
        where P: AsRef<Path>
    {
        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create(true)
            .append(true)
            .open(p));
        Ok(Log {
            f: f,
            max_bytes: max_bytes,
            pos: 0,
        })
    }

    pub fn can_write(&self) -> bool {
        self.pos < self.max_bytes
    }

    pub fn append(&mut self, msg: Message) -> Result<u32, LogAppendError> {
        // ensure we won't go over the max
        if msg.bytes().len() + self.pos > self.max_bytes {
            return Err(LogAppendError::LogFull);
        }

        try!(self.f.write_all(msg.bytes()));
        let write_pos = self.pos;
        self.pos += msg.bytes().len();
        Ok(write_pos as u32)
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.f.flush()
    }
}

pub struct Segment {
    log: Log,
    index: Index,
    next_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IndexError(IndexWriteError),
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

impl From<LogAppendError> for SegmentAppendError {
    #[inline]
    fn from(e: LogAppendError) -> SegmentAppendError {
        match e {
            LogAppendError::LogFull => SegmentAppendError::LogFull,
            LogAppendError::IoError(e) => SegmentAppendError::IoError(e),
        }
    }
}

impl From<IndexWriteError> for SegmentAppendError {
    #[inline]
    fn from(e: IndexWriteError) -> SegmentAppendError {
        SegmentAppendError::IndexError(e)
    }
}

impl Segment {
    // TODO: open variant for reading

    pub fn new<P>(log_dir: P,
                  base_offset: u64,
                  max_bytes: usize,
                  index_bytes: usize)
                  -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log = {
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("log");
            try!(Log::new(&path_buf, max_bytes))
        };

        let index = {
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("index");
            try!(Index::new(&path_buf, index_bytes as u64, base_offset))
        };

        Ok(Segment {
            log: log,
            index: index,
            next_offset: base_offset,
        })
    }

    #[inline]
    pub fn next_offset(&self) -> u64 {
        self.next_offset
    }

    pub fn append(&mut self, msg: &[u8]) -> Result<u64, SegmentAppendError> {
        if !self.index.can_write() || !self.log.can_write() {
            return Err(SegmentAppendError::LogFull);
        }

        let off = self.next_offset;
        let pos = try!(self.log.append(Message::new(msg, off)));
        try!(self.index.append(off, pos));

        self.next_offset += 1;
        Ok(off)
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        try!(self.index.flush_sync());
        self.log.flush()
    }
}

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

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn index() {
        let index_path = "target/.test-index";

        // remove before running (may be around from failing test run)
        fs::remove_file(index_path).unwrap_or(());

        {
            let mut index = Index::new(index_path, 1000u64, 10u64).unwrap();
            assert_eq!(1000, index.size());
            index.append(11u64, 0xffff).unwrap();
            index.append(12u64, 0xeeee).unwrap();
            index.flush_sync().unwrap();
        }

        // reopen it for read
        {
            let index = Index::new(index_path, 1000u64, 10u64).unwrap();

            let e0 = index.read_entry(0).unwrap().unwrap();
            assert_eq!(1u32, e0.relative_offset());
            assert_eq!(11u64, e0.offset());
            assert_eq!(0xffff, e0.file_position());

            let e1 = index.read_entry(1).unwrap().unwrap();
            assert_eq!(2u32, e1.relative_offset());
            assert_eq!(12u64, e1.offset());
            assert_eq!(0xeeee, e1.file_position());

            // read an entry that does not exist
            let e2 = index.read_entry(2).unwrap();
            assert_eq!(None, e2);
        }
        fs::remove_file(index_path).unwrap();
    }

    #[test]
    pub fn log() {
        let log_path = "target/.test-log";
        fs::remove_file(log_path).unwrap_or(());
        {
            let mut f = Log::new(log_path, 1024).unwrap();

            let m0 = Message::new(b"12345", 1000);
            assert_eq!(m0.bytes().len(), 21);
            let p0 = f.append(m0).unwrap();
            assert_eq!(p0, 0);

            let m1 = Message::new(b"66666", 1001);
            let p1 = f.append(m1).unwrap();
            assert_eq!(p1, 21);

            f.flush().unwrap();
        }
        fs::remove_file(log_path).unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let log_path = "target/test-log";
        fs::remove_dir_all(log_path).unwrap_or(());
        fs::create_dir_all(log_path).unwrap_or(());

        let mut seg = Segment::new(log_path, 100u64, 100 * 1024 * 1024, 10 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });

        fs::remove_dir_all(log_path).unwrap_or(());
    }
}
<commit_msg>Require new log<commit_after>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use memmap::{Mmap, Protection};
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write};
use std;

// TODO: ...
// pub type Offset(u64);

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

/// An index is a file with pairs of relative offset to file position offset
/// messages. Both are stored as 4 bytes.
pub struct Index {
    file: File,
    mmap: Mmap,

    /// next starting byte in index file offset to write
    next_write_offset: usize,
    base_offset: u64,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IndexEntry {
    rel_offset: u32,
    base_offset: u64,
    file_pos: u32,
}

impl IndexEntry {
    pub fn relative_offset(&self) -> u32 {
        self.rel_offset
    }

    #[inline]
    pub fn offset(&self) -> u64 {
        self.base_offset + (self.rel_offset as u64)
    }

    #[inline]
    pub fn file_position(&self) -> u32 {
        self.file_pos
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IndexWriteError {
    IndexFull,
    OffsetLessThanBase,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IndexReadError {
    OutOfBounds,
}

impl Index {
    pub fn new<P>(path: P, file_bytes: u64, base_offset: u64) -> io::Result<Index>
        where P: AsRef<Path>
    {
        // open the file, expecting to create it
        let index_file = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .append(true)
            .create(true)
            .open(path));

        // read the metadata and truncate
        let meta = try!(index_file.metadata());
        let len = meta.len();
        if len == 0 {
            try!(index_file.set_len(file_bytes));
        }

        let mmap = try!(Mmap::open(&index_file, Protection::ReadWrite));

        Ok(Index {
            file: index_file,
            mmap: mmap,
            next_write_offset: len as usize,
            base_offset: base_offset,
        })
    }

    #[inline]
    pub fn can_write(&self) -> bool {
        self.size() >= (self.next_write_offset + 8)
    }

    #[inline]
    pub fn size(&self) -> usize {
        self.mmap.len()
    }

    pub fn append(&mut self, abs_offset: u64, position: u32) -> Result<(), IndexWriteError> {
        // TODO: test to ensure abs_offset is < last offset written (invariant of the index)
        if !self.can_write() {
            return Err(IndexWriteError::IndexFull);
        }

        if abs_offset < self.base_offset {
            return Err(IndexWriteError::OffsetLessThanBase);
        }

        unsafe {
            let mem_slice: &mut [u8] = self.mmap.as_mut_slice();
            let offset = (abs_offset - self.base_offset) as u32;
            let buf_pos = self.next_write_offset;

            BigEndian::write_u32(&mut mem_slice[buf_pos..buf_pos + 4], offset);
            BigEndian::write_u32(&mut mem_slice[buf_pos + 4..buf_pos + 8], position);

            self.next_write_offset += 8;

            Ok(())
        }
    }

    pub fn flush_sync(&mut self) -> io::Result<()> {
        try!(self.mmap.flush());
        self.file.flush()
    }

    pub fn read_entry(&self, i: usize) -> Result<Option<IndexEntry>, IndexReadError> {
        if self.size() < (i + 1) * 8 {
            return Err(IndexReadError::OutOfBounds);
        }

        unsafe {
            let mem_slice = self.mmap.as_slice();
            let start = i * 8;
            let offset = BigEndian::read_u32(&mem_slice[start..start + 4]);
            if offset == 0 && i > 0 {
                Ok(None)
            } else {
                let pos = BigEndian::read_u32(&mem_slice[start + 4..start + 8]);
                Ok(Some(IndexEntry {
                    rel_offset: offset,
                    base_offset: self.base_offset,
                    file_pos: pos,
                }))
            }
        }
    }
}

pub struct Log {
    f: File,
    max_bytes: usize,
    pos: usize,
}

#[derive(Debug)]
pub enum LogAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<std::io::Error> for LogAppendError {
    #[inline]
    fn from(e: std::io::Error) -> LogAppendError {
        LogAppendError::IoError(e)
    }
}

impl Log {
    pub fn new<P>(p: P, max_bytes: usize) -> io::Result<Log>
        where P: AsRef<Path>
    {
        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(p));
        Ok(Log {
            f: f,
            max_bytes: max_bytes,
            pos: 0,
        })
    }

    pub fn can_write(&self) -> bool {
        self.pos < self.max_bytes
    }

    pub fn append(&mut self, msg: Message) -> Result<u32, LogAppendError> {
        // ensure we won't go over the max
        if msg.bytes().len() + self.pos > self.max_bytes {
            return Err(LogAppendError::LogFull);
        }

        try!(self.f.write_all(msg.bytes()));
        let write_pos = self.pos;
        self.pos += msg.bytes().len();
        Ok(write_pos as u32)
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.f.flush()
    }
}

pub struct Segment {
    log: Log,
    index: Index,
    next_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IndexError(IndexWriteError),
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

impl From<LogAppendError> for SegmentAppendError {
    #[inline]
    fn from(e: LogAppendError) -> SegmentAppendError {
        match e {
            LogAppendError::LogFull => SegmentAppendError::LogFull,
            LogAppendError::IoError(e) => SegmentAppendError::IoError(e),
        }
    }
}

impl From<IndexWriteError> for SegmentAppendError {
    #[inline]
    fn from(e: IndexWriteError) -> SegmentAppendError {
        SegmentAppendError::IndexError(e)
    }
}

impl Segment {
    // TODO: open variant for reading

    pub fn new<P>(log_dir: P,
                  base_offset: u64,
                  max_bytes: usize,
                  index_bytes: usize)
                  -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log = {
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("log");
            try!(Log::new(&path_buf, max_bytes))
        };

        let index = {
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("index");
            try!(Index::new(&path_buf, index_bytes as u64, base_offset))
        };

        Ok(Segment {
            log: log,
            index: index,
            next_offset: base_offset,
        })
    }

    #[inline]
    pub fn next_offset(&self) -> u64 {
        self.next_offset
    }

    pub fn append(&mut self, msg: &[u8]) -> Result<u64, SegmentAppendError> {
        if !self.index.can_write() || !self.log.can_write() {
            return Err(SegmentAppendError::LogFull);
        }

        let off = self.next_offset;
        let pos = try!(self.log.append(Message::new(msg, off)));
        try!(self.index.append(off, pos));

        self.next_offset += 1;
        Ok(off)
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        try!(self.index.flush_sync());
        self.log.flush()
    }
}

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

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn index() {
        let index_path = "target/.test-index";

        // remove before running (may be around from failing test run)
        fs::remove_file(index_path).unwrap_or(());

        {
            let mut index = Index::new(index_path, 1000u64, 10u64).unwrap();
            assert_eq!(1000, index.size());
            index.append(11u64, 0xffff).unwrap();
            index.append(12u64, 0xeeee).unwrap();
            index.flush_sync().unwrap();
        }

        // reopen it for read
        {
            let index = Index::new(index_path, 1000u64, 10u64).unwrap();

            let e0 = index.read_entry(0).unwrap().unwrap();
            assert_eq!(1u32, e0.relative_offset());
            assert_eq!(11u64, e0.offset());
            assert_eq!(0xffff, e0.file_position());

            let e1 = index.read_entry(1).unwrap().unwrap();
            assert_eq!(2u32, e1.relative_offset());
            assert_eq!(12u64, e1.offset());
            assert_eq!(0xeeee, e1.file_position());

            // read an entry that does not exist
            let e2 = index.read_entry(2).unwrap();
            assert_eq!(None, e2);
        }
        fs::remove_file(index_path).unwrap();
    }

    #[test]
    pub fn log() {
        let log_path = "target/.test-log";
        fs::remove_file(log_path).unwrap_or(());
        {
            let mut f = Log::new(log_path, 1024).unwrap();

            let m0 = Message::new(b"12345", 1000);
            assert_eq!(m0.bytes().len(), 21);
            let p0 = f.append(m0).unwrap();
            assert_eq!(p0, 0);

            let m1 = Message::new(b"66666", 1001);
            let p1 = f.append(m1).unwrap();
            assert_eq!(p1, 21);

            f.flush().unwrap();
        }
        fs::remove_file(log_path).unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let log_path = "target/test-log";
        fs::remove_dir_all(log_path).unwrap_or(());
        fs::create_dir_all(log_path).unwrap_or(());

        let mut seg = Segment::new(log_path, 100u64, 100 * 1024 * 1024, 10 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });

        fs::remove_dir_all(log_path).unwrap_or(());
    }
}
<|endoftext|>


<commit_before>//! Generates descriptors structure for unstable feature from Unstable Book

use crate::{
    codegen::{self, project_root, Mode, Result},
};
use std::process::Command;
use std::fs;
use std::path::{Path, PathBuf};
use walkdir::{DirEntry, WalkDir};
use quote::{format_ident, quote};
use crate::codegen::update;

pub fn generate_unstable_future_descriptor(mode: Mode) -> Result<()> {
    let path = project_root().join(codegen::STORAGE);
    fs::create_dir_all(path.clone())?;

    Command::new("git").current_dir(path.clone()).arg("init").output()?;
    Command::new("git").current_dir(path.clone()).args(&["remote", "add", "-f", "origin", codegen::REPOSITORY_URL]).output()?;
    Command::new("git").current_dir(path.clone()).args(&["sparse-checkout", "set", "/src/doc/unstable-book/src/"]).output()?;
    Command::new("git").current_dir(path.clone()).args(&["pull", "origin", "master"]).output()?;
    //TODO: check git, and do pull

    let src_dir = path.join("src/doc/unstable-book/src");
    let files = WalkDir::new(src_dir.join("language-features"))
        .into_iter()
        .chain(WalkDir::new(src_dir.join("library-features")))
        .filter_map(|e| e.ok())
        .filter(|entry| {
            // Get all `.md ` files
            entry.file_type().is_file() && entry.path().extension().map(|ext| ext == "md").unwrap_or(false)
        })
        .collect::<Vec<_>>();

    let definitions = files.iter().map(|entry| {
        let path = entry.path();
        let feature_ident = format!("{}", path.file_stem().unwrap().to_str().unwrap().replace("-", "_"));
        let doc = format!("{}", std::fs::read_to_string(path).unwrap() );

        quote!{ LintCompletion { label: #feature_ident, description: #doc } }
    }).collect::<Vec<_>>();

    let ts = quote! {
        use crate::completion::LintCompletion;

        pub const UNSTABLE_FEATURE_DESCRIPTOR:  &[LintCompletion] = &[
            #(#definitions),*
        ];
    };

    let destination = project_root().join(codegen::UNSTABLE_FEATURE);
    let contents = crate::reformat(ts.to_string())?;
    update(destination.as_path(), &contents, mode)?;

    Ok(())
}<commit_msg>fix unused<commit_after>//! Generates descriptors structure for unstable feature from Unstable Book

use crate::{
    codegen::{self, project_root, Mode, Result},
};
use std::process::Command;
use std::fs;
use walkdir::WalkDir;
use quote::quote;
use crate::codegen::update;

pub fn generate_unstable_future_descriptor(mode: Mode) -> Result<()> {
    let path = project_root().join(codegen::STORAGE);
    fs::create_dir_all(path.clone())?;

    Command::new("git").current_dir(path.clone()).arg("init").output()?;
    Command::new("git").current_dir(path.clone()).args(&["remote", "add", "-f", "origin", codegen::REPOSITORY_URL]).output()?;
    Command::new("git").current_dir(path.clone()).args(&["sparse-checkout", "set", "/src/doc/unstable-book/src/"]).output()?;
    Command::new("git").current_dir(path.clone()).args(&["pull", "origin", "master"]).output()?;
    //TODO: check git, and do pull

    let src_dir = path.join("src/doc/unstable-book/src");
    let files = WalkDir::new(src_dir.join("language-features"))
        .into_iter()
        .chain(WalkDir::new(src_dir.join("library-features")))
        .filter_map(|e| e.ok())
        .filter(|entry| {
            // Get all `.md ` files
            entry.file_type().is_file() && entry.path().extension().map(|ext| ext == "md").unwrap_or(false)
        })
        .collect::<Vec<_>>();

    let definitions = files.iter().map(|entry| {
        let path = entry.path();
        let feature_ident = format!("{}", path.file_stem().unwrap().to_str().unwrap().replace("-", "_"));
        let doc = format!("{}", std::fs::read_to_string(path).unwrap() );

        quote!{ LintCompletion { label: #feature_ident, description: #doc } }
    }).collect::<Vec<_>>();

    let ts = quote! {
        use crate::completion::LintCompletion;

        pub const UNSTABLE_FEATURE_DESCRIPTOR:  &[LintCompletion] = &[
            #(#definitions),*
        ];
    };

    let destination = project_root().join(codegen::UNSTABLE_FEATURE);
    let contents = crate::reformat(ts.to_string())?;
    update(destination.as_path(), &contents, mode)?;

    Ok(())
}<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use std::slice;
use libc::c_void;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t, bool);

impl Surface {
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr, false)
    }

    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, true)
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, false)
    }

    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe {
            Self::from_raw_full(ffi::cairo_surface_create_similar(self.0,
                                                                  content.into(),
                                                                  width,
                                                                  height))
        }
    }

    pub fn get_mime_data(&self, mime_type: &str) -> Option<Vec<u8>> {
        let mut data_ptr: *mut u8 = ptr::null_mut();
        let mut length = 0u64;
        unsafe {
            ffi::cairo_surface_get_mime_data(
                self.to_raw_none(),
                mime_type.to_glib_none().0,
                &mut data_ptr,
                &mut length,
            );
            if !data_ptr.is_null() && length != 0 {
                Some(slice::from_raw_parts(
                    data_ptr as *const u8,
                    length as usize,
                ).to_vec())
            } else {
                None
            }
        }
    }

    pub fn set_mime_data<T: AsRef<[u8]> + Send + 'static>(
        &self,
        mime_type: &str,
        slice: T) -> Result<(), Status> {
        let b = Box::new(slice);
        let (size, data) = {
            let slice = (*b).as_ref();
            (slice.len(), slice.as_ptr())
        };

        let user_data = Box::into_raw(b);

        let status = unsafe {
                ffi::cairo_surface_set_mime_data(self.to_raw_none(),
                mime_type.to_glib_none().0,
                data,
                size as u64,
                Some(unbox::<T>),
                user_data as *mut _,
            )
        };

        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }

    pub fn supports_mime_type(&self, mime_type: &str) -> bool {
        unsafe {
            ffi::cairo_surface_supports_mime_type(self.0, mime_type.to_glib_none().0).as_bool()
        }
    }
}

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.to_raw_none())
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Surface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_surface_destroy(self.0); }
        }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
    fn status(&self) -> Status;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.as_ref().0)) }
    }

    fn status(&self) -> Status {
        unsafe { Status::from(ffi::cairo_surface_status(self.as_ref().0)) }
    }
}

pub(crate) trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let ptr: *mut T = Box::into_raw(data);

        assert_eq!(mem::size_of::<*mut c_void>(), mem::size_of_val(&ptr));

        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, key as *const _ as *mut _,
            ptr as *mut c_void, Some(unbox::<T>));
        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern "C" fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = Box::from_raw(data as *mut T);
    drop(data);
}

#[cfg(test)]
mod tests {
    use Format;
    use ImageSurface;
    use constants::MIME_TYPE_PNG;

    #[test]
    fn mime_data() {
        let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap();
        let data = surface.get_mime_data(MIME_TYPE_PNG);
        /* Initially the data for any mime type has to be none */
        assert!(data.is_none());

        assert!(surface.set_mime_data(MIME_TYPE_PNG, &[1u8, 10u8]).is_ok());
        let data = surface.get_mime_data(MIME_TYPE_PNG).unwrap();
        assert_eq!(data, &[1u8, 10u8]);
    }
}
<commit_msg>use CString instead of to_glib_none()<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use std::slice;
use libc::c_void;
use std::ffi::CString;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t, bool);

impl Surface {
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr, false)
    }

    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, true)
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, false)
    }

    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe {
            Self::from_raw_full(ffi::cairo_surface_create_similar(self.0,
                                                                  content.into(),
                                                                  width,
                                                                  height))
        }
    }

    pub fn get_mime_data(&self, mime_type: &str) -> Option<Vec<u8>> {
        let mut data_ptr: *mut u8 = std::ptr::null_mut();
        let mut length = 0u64;
        unsafe {
            let mime_type = CString::new(mime_type).unwrap();
            ffi::cairo_surface_get_mime_data(
                self.to_raw_none(),
                mime_type.as_ptr(),
                &mut data_ptr,
                &mut length,
            );
            if !data_ptr.is_null() && length != 0 {
                Some(slice::from_raw_parts(
                    data_ptr as *const u8,
                    length as usize,
                ).to_vec())
            } else {
                None
            }
        }
    }

    pub fn set_mime_data<T: AsRef<[u8]> + Send + 'static>(
        &self,
        mime_type: &str,
        slice: T) -> Result<(), Status> {
        let b = Box::new(slice);
        let (size, data) = {
            let slice = (*b).as_ref();
            (slice.len(), slice.as_ptr())
        };

        let user_data = Box::into_raw(b);

        let status = unsafe {
            let mime_type = CString::new(mime_type).unwrap();
            ffi::cairo_surface_set_mime_data(self.to_raw_none(),
                mime_type.as_ptr(),
                data,
                size as u64,
                Some(unbox::<T>),
                user_data as *mut _,
            )
        };

        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }

    pub fn supports_mime_type(&self, mime_type: &str) -> bool {
        unsafe {
            let mime_type = CString::new(mime_type).unwrap();
            ffi::cairo_surface_supports_mime_type(self.0, mime_type.as_ptr()).as_bool()
        }
    }
}

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.to_raw_none())
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Surface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_surface_destroy(self.0); }
        }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
    fn status(&self) -> Status;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.as_ref().0)) }
    }

    fn status(&self) -> Status {
        unsafe { Status::from(ffi::cairo_surface_status(self.as_ref().0)) }
    }
}

pub(crate) trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let ptr: *mut T = Box::into_raw(data);

        assert_eq!(mem::size_of::<*mut c_void>(), mem::size_of_val(&ptr));

        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, key as *const _ as *mut _,
            ptr as *mut c_void, Some(unbox::<T>));
        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern "C" fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = Box::from_raw(data as *mut T);
    drop(data);
}

#[cfg(test)]
mod tests {
    use Format;
    use ImageSurface;
    use constants::MIME_TYPE_PNG;

    #[test]
    fn mime_data() {
        let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap();
        let data = surface.get_mime_data(MIME_TYPE_PNG);
        /* Initially the data for any mime type has to be none */
        assert!(data.is_none());

        assert!(surface.set_mime_data(MIME_TYPE_PNG, &[1u8, 10u8]).is_ok());
        let data = surface.get_mime_data(MIME_TYPE_PNG).unwrap();
        assert_eq!(data, &[1u8, 10u8]);
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactor sandbox code to reduce duplication<commit_after><|endoftext|>


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

use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedMatrix4D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
    fn is_identity(&self) -> bool;
    fn preserves_2d_axis_alignment(&self) -> bool;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedMatrix4D<f32, Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
    }

    fn is_identity(&self) -> bool {
        *self == TypedMatrix4D::identity()
    }

    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }
}

pub trait RectHelpers<U> where Self: Sized {
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {

    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x &&
        self.origin.y <= other.origin.y &&
        self.max_x() >= other.max_x() &&
        self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(TypedPoint2D::new(x0, y0),
                       TypedSize2D::new(x1 - x0, y1 - y0))
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N:PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[inline]
pub fn rect_from_points_f(x0: f32,
                          y0: f32,
                          x1: f32,
                          y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0),
              Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn subtract_rect<U>(rect: &TypedRect<f32, U>,
                        other: &TypedRect<f32, U>,
                        results: &mut Vec<TypedRect<f32, U>>) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

pub fn get_normal(x: f32) -> Option<f32> {
    if x.is_normal() {
        Some(x)
    } else {
        None
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[derive(Debug, Clone)]
pub struct TransformedRect {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
    pub inner_rect: DeviceIntRect,
    pub vertices: [WorldPoint4D; 4],
    pub kind: TransformedRectKind,
}

impl TransformedRect {
    pub fn new(rect: &LayerRect,
               transform: &LayerToWorldTransform,
               device_pixel_ratio: f32) -> TransformedRect {

        let kind = if transform.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        };

        // FIXME(gw): This code is meant to be a fast path for simple transforms.
        // However, it fails on transforms that translate Z but result in an
        // axis aligned rect.

/*
        match kind {
            TransformedRectKind::AxisAligned => {
                let v0 = transform.transform_point(&rect.origin);
                let v1 = transform.transform_point(&rect.top_right());
                let v2 = transform.transform_point(&rect.bottom_left());
                let v3 = transform.transform_point(&rect.bottom_right());

                let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
                                                 DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
                let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
                                                 DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));

                let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
                                                                          screen_max_dp.y - screen_min_dp.y));

                TransformedRect {
                    local_rect: *rect,
                    vertices: [
                        Point4D::new(v0.x, v0.y, 0.0, 1.0),
                        Point4D::new(v1.x, v1.y, 0.0, 1.0),
                        Point4D::new(v2.x, v2.y, 0.0, 1.0),
                        Point4D::new(v3.x, v3.y, 0.0, 1.0),
                    ],
                    bounding_rect: screen_rect_dp,
                    kind: kind,
                }
            }
            TransformedRectKind::Complex => {
                */
                let vertices = [
                    transform.transform_point4d(&LayerPoint4D::new(rect.origin.x,
                                                                   rect.origin.y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_left().x,
                                                                   rect.bottom_left().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_right().x,
                                                                   rect.bottom_right().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.top_right().x,
                                                                   rect.top_right().y,
                                                                   0.0,
                                                                   1.0)),
                ];

                let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

                for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
                    let inv_w = 1.0 / vertex.w;
                    *x = get_normal(vertex.x * inv_w).unwrap_or(0.0);
                    *y = get_normal(vertex.y * inv_w).unwrap_or(0.0);
                }

                xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
                ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

                let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
                                                       (ys[0] * device_pixel_ratio).floor() as i32);
                let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
                                                       (ys[3] * device_pixel_ratio).ceil() as i32);
                let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
                                                       (ys[1] * device_pixel_ratio).ceil() as i32);
                let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
                                                       (ys[2] * device_pixel_ratio).floor() as i32);

                TransformedRect {
                    local_rect: *rect,
                    vertices: vertices,
                    bounding_rect: DeviceIntRect::new(outer_min_dp,
                                                      DeviceIntSize::new(outer_max_dp.x - outer_min_dp.x,
                                                                         outer_max_dp.y - outer_min_dp.y)),
                    inner_rect: DeviceIntRect::new(inner_min_dp,
                                                   DeviceIntSize::new(inner_max_dp.x - inner_min_dp.x,
                                                                      inner_max_dp.y - inner_min_dp.y)),
                    kind: kind,
                }
                /*
            }
        }*/
    }
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

pub trait ComplexClipRegionHelpers {
    /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    /// any of the bounding rectangles of the rounded corners.
    fn get_inner_rect_safe(&self) -> Option<LayoutRect>;
    /// Return the approximately largest aligned rectangle that is fully inside
    /// the provided clip region.
    fn get_inner_rect_full(&self) -> Option<LayoutRect>;
}

impl ComplexClipRegionHelpers for ComplexClipRegion {
    fn get_inner_rect_safe(&self) -> Option<LayoutRect> {
        // value of `k==1.0` is used for extraction of the corner rectangles
        // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
        extract_inner_rect_impl(&self.rect, &self.radii, 1.0)
    }

    fn get_inner_rect_full(&self) -> Option<LayoutRect> {
        // this `k` optimal for a simple case of all border radii being equal
        let k = 1.0 - 0.5 * FRAC_1_SQRT_2; // could be nicely approximated to `0.3`
        extract_inner_rect_impl(&self.rect, &self.radii, k)
    }
}

#[inline]
fn extract_inner_rect_impl<U>(rect: &TypedRect<f32, U>,
                              radii: &BorderRadius,
                              k: f32) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb = (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
             TypedSize2D::new(xr-xl, yb-yt)))
    } else {
        None
    }
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}
<commit_msg>Overflowing protection for TransformedRect<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedMatrix4D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
    fn is_identity(&self) -> bool;
    fn preserves_2d_axis_alignment(&self) -> bool;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedMatrix4D<f32, Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
    }

    fn is_identity(&self) -> bool {
        *self == TypedMatrix4D::identity()
    }

    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }
}

pub trait RectHelpers<U> where Self: Sized {
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {

    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x &&
        self.origin.y <= other.origin.y &&
        self.max_x() >= other.max_x() &&
        self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(TypedPoint2D::new(x0, y0),
                       TypedSize2D::new(x1 - x0, y1 - y0))
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N:PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[inline]
pub fn rect_from_points_f(x0: f32,
                          y0: f32,
                          x1: f32,
                          y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0),
              Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn subtract_rect<U>(rect: &TypedRect<f32, U>,
                        other: &TypedRect<f32, U>,
                        results: &mut Vec<TypedRect<f32, U>>) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

pub fn get_normal(x: f32) -> Option<f32> {
    if x.is_normal() {
        Some(x)
    } else {
        None
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[derive(Debug, Clone)]
pub struct TransformedRect {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
    pub inner_rect: DeviceIntRect,
    pub vertices: [WorldPoint4D; 4],
    pub kind: TransformedRectKind,
}

impl TransformedRect {
    pub fn new(rect: &LayerRect,
               transform: &LayerToWorldTransform,
               device_pixel_ratio: f32) -> TransformedRect {

        let kind = if transform.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        };

        // FIXME(gw): This code is meant to be a fast path for simple transforms.
        // However, it fails on transforms that translate Z but result in an
        // axis aligned rect.

/*
        match kind {
            TransformedRectKind::AxisAligned => {
                let v0 = transform.transform_point(&rect.origin);
                let v1 = transform.transform_point(&rect.top_right());
                let v2 = transform.transform_point(&rect.bottom_left());
                let v3 = transform.transform_point(&rect.bottom_right());

                let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
                                                 DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
                let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
                                                 DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));

                let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
                                                                          screen_max_dp.y - screen_min_dp.y));

                TransformedRect {
                    local_rect: *rect,
                    vertices: [
                        Point4D::new(v0.x, v0.y, 0.0, 1.0),
                        Point4D::new(v1.x, v1.y, 0.0, 1.0),
                        Point4D::new(v2.x, v2.y, 0.0, 1.0),
                        Point4D::new(v3.x, v3.y, 0.0, 1.0),
                    ],
                    bounding_rect: screen_rect_dp,
                    kind: kind,
                }
            }
            TransformedRectKind::Complex => {
                */
                let vertices = [
                    transform.transform_point4d(&LayerPoint4D::new(rect.origin.x,
                                                                   rect.origin.y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_left().x,
                                                                   rect.bottom_left().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_right().x,
                                                                   rect.bottom_right().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.top_right().x,
                                                                   rect.top_right().y,
                                                                   0.0,
                                                                   1.0)),
                ];

                let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

                for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
                    let inv_w = 1.0 / vertex.w;
                    *x = get_normal(vertex.x * inv_w).unwrap_or(0.0);
                    *y = get_normal(vertex.y * inv_w).unwrap_or(0.0);
                }

                xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
                ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

                let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
                                                       (ys[0] * device_pixel_ratio).floor() as i32);
                let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
                                                       (ys[3] * device_pixel_ratio).ceil() as i32);
                let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
                                                       (ys[1] * device_pixel_ratio).ceil() as i32);
                let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
                                                       (ys[2] * device_pixel_ratio).floor() as i32);

                TransformedRect {
                    local_rect: *rect,
                    vertices: vertices,
                    bounding_rect: DeviceIntRect::new(outer_min_dp,
                                                      DeviceIntSize::new(outer_max_dp.x.saturating_sub(outer_min_dp.x),
                                                                         outer_max_dp.y.saturating_sub(outer_min_dp.y))),
                    inner_rect: DeviceIntRect::new(inner_min_dp,
                                                   DeviceIntSize::new(inner_max_dp.x.saturating_sub(inner_min_dp.x),
                                                                      inner_max_dp.y.saturating_sub(inner_min_dp.y))),
                    kind: kind,
                }
                /*
            }
        }*/
    }
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

pub trait ComplexClipRegionHelpers {
    /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    /// any of the bounding rectangles of the rounded corners.
    fn get_inner_rect_safe(&self) -> Option<LayoutRect>;
    /// Return the approximately largest aligned rectangle that is fully inside
    /// the provided clip region.
    fn get_inner_rect_full(&self) -> Option<LayoutRect>;
}

impl ComplexClipRegionHelpers for ComplexClipRegion {
    fn get_inner_rect_safe(&self) -> Option<LayoutRect> {
        // value of `k==1.0` is used for extraction of the corner rectangles
        // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
        extract_inner_rect_impl(&self.rect, &self.radii, 1.0)
    }

    fn get_inner_rect_full(&self) -> Option<LayoutRect> {
        // this `k` optimal for a simple case of all border radii being equal
        let k = 1.0 - 0.5 * FRAC_1_SQRT_2; // could be nicely approximated to `0.3`
        extract_inner_rect_impl(&self.rect, &self.radii, k)
    }
}

#[inline]
fn extract_inner_rect_impl<U>(rect: &TypedRect<f32, U>,
                              radii: &BorderRadius,
                              k: f32) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb = (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
             TypedSize2D::new(xr-xl, yb-yt)))
    } else {
        None
    }
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}
<|endoftext|>


<commit_before>use std::mem;

use misc::*;

#[ repr (C) ]
struct BinaryHeader {

	name: [u8; 100],
	mode: [u8; 8],
	uid: [u8; 8],
	gid: [u8; 8],
	size: [u8; 12],
	mtime: [u8; 12],
	cksum: [u8; 8],
	typeflag: [u8; 1],
	linkname: [u8; 100],
	magic: [u8; 6],
	version: [u8; 2],
	uname: [u8; 32],
	gname: [u8; 32],
	dev_major: [u8; 8],
	dev_minor: [u8; 8],
	atime: [u8; 12],
	ctime: [u8; 12],
	offset: [u8; 12],
	longnames: [u8; 4],
	unused: [u8; 1],
	sparse: [BinarySparseHeader; 4],
	isextended: [u8; 1],
	realsize: [u8; 12],
	pad: [u8; 17],

}

#[ repr (C) ]
struct BinarySparseHeader {

	offset: [u8; 12],
	numbytes: [u8; 12],

}

pub struct Header {

	pub name: Vec <u8>,
	pub mode: u32,
	pub uid: u32,
	pub gid: u32,
	pub size: u64,
	pub mtime: u64,
	pub cksum: u32,
	pub typeflag: Type,
	pub linkname: Vec <u8>,
	pub uname: Vec <u8>,
	pub gname: Vec <u8>,
	pub dev_major: u32,
	pub dev_minor: u32,
	pub atime: u64,
	pub ctime: u64,
	pub offset: u64,

}

#[ derive (Debug) ]
pub enum Type {

	Regular,
	Link,
	SymbolicLink,
	CharacterSpecial,
	BlockSpecial,
	Directory,
	Fifo,

}

impl Header {

	pub fn read (
		header_bytes: & [u8; 512],
	) -> Result <Header, TfError> {

		let binary_header: BinaryHeader =
			unsafe { mem::transmute (* header_bytes) };

		if binary_header.magic != * b"ustar " {

			Err (TfError {
				error_message: format! (
					"Unrecognised tar format: {:?} {:?}",
					binary_header.magic,
					binary_header.version),
			})

		} else if binary_header.version != * b" \0" {

			Err (TfError {
				error_message: format! (
					"Unrecognised gnu tar version: {:?}",
					binary_header.version),
			})

	 	} else {

			Ok (Header {

				name: tar_string (
					& binary_header.name),

				mode: tar_number_u32 (
					& binary_header.mode),

				uid: tar_number_u32 (
					& binary_header.uid),

				gid: tar_number_u32 (
					& binary_header.gid),

				size: tar_number_u64 (
					& binary_header.size),

				mtime: tar_number_u64 (
					& binary_header.mtime),

				cksum: tar_number_u32 (
					& binary_header.cksum),

				typeflag: tar_type (
					& binary_header.typeflag),

				linkname: tar_string (
					& binary_header.linkname),

				uname: tar_string (
					& binary_header.uname),

				gname: tar_string (
					& binary_header.gname),

				dev_major: tar_number_u32 (
					& binary_header.dev_major),

				dev_minor: tar_number_u32 (
					& binary_header.dev_minor),

				atime: tar_number_u64 (
					& binary_header.atime),

				ctime: tar_number_u64 (
					& binary_header.ctime),

				offset: tar_number_u64 (
					& binary_header.offset),

/*
				longnames: [u8; 4],
				unused: [u8; 1],
				sparse: [BinarySparseHeader; 4],
				isextended: [u8; 1],
				realsize: [u8; 12],
				pad: [u8; 17],
*/

			})

		}

	}

}

fn tar_string (
	slice: & [u8],
) -> Vec <u8> {

	match slice.iter ().position (
		|index| * index == 0,
	) {

		Some (index) =>
			slice [ .. index ].to_vec (),

		None =>
			slice.to_vec (),

	}

}

fn tar_number_u64 (
	slice: & [u8],
) -> u64 {

	if slice [0] == 0 {
		0
	} else {
		u64::from_str_radix (
			& String::from_utf8 (
				tar_string (slice),
			).unwrap (),
			8,
		).unwrap ()
	}

}

fn tar_number_u32 (
	slice: & [u8],
) -> u32 {

	if slice [0] == 0 {
		0
	} else {
		u32::from_str_radix (
			& String::from_utf8 (
				tar_string (slice),
			).unwrap (),
			8,
		).unwrap ()
	}

}

fn tar_type (
	typeflag: & [u8; 1],
) -> Type {

	match typeflag [0] {

		b'0' => Type::Regular,
		b'1' => Type::Link,
		b'2' => Type::SymbolicLink,
		b'3' => Type::CharacterSpecial,
		b'4' => Type::BlockSpecial,
		b'5' => Type::Directory,
		b'6' => Type::Fifo,

		_ => {

			panic! (
				"Unrecognised typeflag: {:?}",
				typeflag [0])

		}

	}

}
<commit_msg>handle more tar file types<commit_after>use std::mem;

use misc::*;

#[ repr (C) ]
struct BinaryHeader {

	name: [u8; 100],
	mode: [u8; 8],
	uid: [u8; 8],
	gid: [u8; 8],
	size: [u8; 12],
	mtime: [u8; 12],
	cksum: [u8; 8],
	typeflag: [u8; 1],
	linkname: [u8; 100],
	magic: [u8; 6],
	version: [u8; 2],
	uname: [u8; 32],
	gname: [u8; 32],
	dev_major: [u8; 8],
	dev_minor: [u8; 8],
	atime: [u8; 12],
	ctime: [u8; 12],
	offset: [u8; 12],
	longnames: [u8; 4],
	unused: [u8; 1],
	sparse: [BinarySparseHeader; 4],
	isextended: [u8; 1],
	realsize: [u8; 12],
	pad: [u8; 17],

}

#[ repr (C) ]
struct BinarySparseHeader {

	offset: [u8; 12],
	numbytes: [u8; 12],

}

pub struct Header {

	pub name: Vec <u8>,
	pub mode: u32,
	pub uid: u32,
	pub gid: u32,
	pub size: u64,
	pub mtime: u64,
	pub cksum: u32,
	pub typeflag: Type,
	pub linkname: Vec <u8>,
	pub uname: Vec <u8>,
	pub gname: Vec <u8>,
	pub dev_major: u32,
	pub dev_minor: u32,
	pub atime: u64,
	pub ctime: u64,
	pub offset: u64,

}

#[ derive (Debug) ]
pub enum Type {

	Regular,
	Link,
	SymbolicLink,
	CharacterSpecial,
	BlockSpecial,
	Directory,
	Fifo,

	LongName,
	LongLink,

}

impl Header {

	pub fn read (
		header_bytes: & [u8; 512],
	) -> Result <Header, TfError> {

		let binary_header: BinaryHeader =
			unsafe { mem::transmute (* header_bytes) };

		if binary_header.magic != * b"ustar " {

			Err (TfError {
				error_message: format! (
					"Unrecognised tar format: {:?} {:?}",
					binary_header.magic,
					binary_header.version),
			})

		} else if binary_header.version != * b" \0" {

			Err (TfError {
				error_message: format! (
					"Unrecognised gnu tar version: {:?}",
					binary_header.version),
			})

	 	} else {

			Ok (Header {

				name: tar_string (
					& binary_header.name),

				mode: tar_number_u32 (
					& binary_header.mode),

				uid: tar_number_u32 (
					& binary_header.uid),

				gid: tar_number_u32 (
					& binary_header.gid),

				size: tar_number_u64 (
					& binary_header.size),

				mtime: tar_number_u64 (
					& binary_header.mtime),

				cksum: tar_number_u32 (
					& binary_header.cksum),

				typeflag: tar_type (
					& binary_header.typeflag),

				linkname: tar_string (
					& binary_header.linkname),

				uname: tar_string (
					& binary_header.uname),

				gname: tar_string (
					& binary_header.gname),

				dev_major: tar_number_u32 (
					& binary_header.dev_major),

				dev_minor: tar_number_u32 (
					& binary_header.dev_minor),

				atime: tar_number_u64 (
					& binary_header.atime),

				ctime: tar_number_u64 (
					& binary_header.ctime),

				offset: tar_number_u64 (
					& binary_header.offset),

/*
				longnames: [u8; 4],
				unused: [u8; 1],
				sparse: [BinarySparseHeader; 4],
				isextended: [u8; 1],
				realsize: [u8; 12],
				pad: [u8; 17],
*/

			})

		}

	}

}

fn tar_string (
	slice: & [u8],
) -> Vec <u8> {

	match slice.iter ().position (
		|index| * index == 0,
	) {

		Some (index) =>
			slice [ .. index ].to_vec (),

		None =>
			slice.to_vec (),

	}

}

fn tar_number_u64 (
	slice: & [u8],
) -> u64 {

	if slice [0] == 0 {
		0
	} else {
		u64::from_str_radix (
			& String::from_utf8 (
				tar_string (slice),
			).unwrap (),
			8,
		).unwrap ()
	}

}

fn tar_number_u32 (
	slice: & [u8],
) -> u32 {

	if slice [0] == 0 {
		0
	} else {
		u32::from_str_radix (
			& String::from_utf8 (
				tar_string (slice),
			).unwrap (),
			8,
		).unwrap ()
	}

}

fn tar_type (
	typeflag: & [u8; 1],
) -> Type {

	match typeflag [0] {

		b'0' => Type::Regular,
		b'1' => Type::Link,
		b'2' => Type::SymbolicLink,
		b'3' => Type::CharacterSpecial,
		b'4' => Type::BlockSpecial,
		b'5' => Type::Directory,
		b'6' => Type::Fifo,

		b'K' => Type::LongLink,
		b'L' => Type::LongName,

		_ => {

			panic! (
				"Unrecognised typeflag: {:?}",
				typeflag [0])

		}

	}

}
<|endoftext|>


<commit_before>extern crate tajo;

use std::{i8,i16};
use std::rc::Rc;
use std::cell::RefCell;

use tajo::schema::*;
use tajo::eval::{Eval, MapEval};
use tajo::eval::interpreter::*;
use tajo::rows::*;
use tajo::types::*;

pub fn make_test_schema() -> Schema {
  let mut columns = Vec::new();
  columns.push(Column::new("c0".to_string(), Ty::Bool));      // 0
  columns.push(Column::new("c1".to_string(), Ty::Int1));      // 1
  columns.push(Column::new("c2".to_string(), Ty::Int2));      // 2
  columns.push(Column::new("c3".to_string(), Ty::Int4));      // 3
  columns.push(Column::new("c4".to_string(), Ty::Int8));      // 4
  columns.push(Column::new("c5".to_string(), Ty::Float4));    // 5
  columns.push(Column::new("c6".to_string(), Ty::Float8));    // 6
  columns.push(Column::new("c7".to_string(), Ty::Date));      // 7
  columns.push(Column::new("c8".to_string(), Ty::Time));      // 8
  columns.push(Column::new("c9".to_string(), Ty::Timestamp)); // 9

  columns.push(Column::new("c10".to_string(), Ty::Text));     // 10
  // columns.push(Column::new_with_len("c12".to_string(), Ty::VARCHAR, 4));
  // columns.push(Column::new_with_len("c13".to_string(), Ty::CHAR, 4));

  Schema::new(columns)
}

pub fn fill_vector_block(rowblock: &mut RowBlock) {
  for i in (0..1024) {
    rowblock.put_int1(1, i, (i % (i8::MAX - 1) as usize) as i8);
    rowblock.put_int2(2, i, (i % (i16::MAX -1) as usize) as i16);
    rowblock.put_int4(3, i, i as i32);
    rowblock.put_int8(4, i, i as i64);
    rowblock.put_float4(5, i, i as f32);
    rowblock.put_float8(6, i, i as f64);
    rowblock.put_date(7, i, i as i32);
    rowblock.put_time(8, i, i as i64);
    rowblock.put_timestamp(9, i, i as i64);

    rowblock.put_text(10, i, &"Rust");
  }
}

#[test]
fn test_field() {
  let schema = make_test_schema();

  let mut field: Box<MapEval> = Box::new(Field::new(&Column::new("c3".to_string(), Ty::Int4)));
  let mut r: Box<RowBlock> = Box::new(AllocatedVecRowBlock::new(schema.clone()));
  fill_vector_block(&mut *r);

  assert!(field.bind(&schema).is_ok());
  let v: &Vector = field.eval(&*r);
}<commit_msg>Completed test_FieldEval().<commit_after>extern crate tajo;

use std::{i8,i16};

use tajo::schema::*;
use tajo::eval::{Eval, MapEval};
use tajo::eval::interpreter::*;
use tajo::rows::*;
use tajo::rows::vector::as_array;
use tajo::types::*;

pub fn make_test_schema() -> Schema {
  let mut columns = Vec::new();
  columns.push(Column::new("c0".to_string(), Ty::Bool));      // 0
  columns.push(Column::new("c1".to_string(), Ty::Int1));      // 1
  columns.push(Column::new("c2".to_string(), Ty::Int2));      // 2
  columns.push(Column::new("c3".to_string(), Ty::Int4));      // 3
  columns.push(Column::new("c4".to_string(), Ty::Int8));      // 4
  columns.push(Column::new("c5".to_string(), Ty::Float4));    // 5
  columns.push(Column::new("c6".to_string(), Ty::Float8));    // 6
  columns.push(Column::new("c7".to_string(), Ty::Date));      // 7
  columns.push(Column::new("c8".to_string(), Ty::Time));      // 8
  columns.push(Column::new("c9".to_string(), Ty::Timestamp)); // 9

  columns.push(Column::new("c10".to_string(), Ty::Text));     // 10
  // columns.push(Column::new_with_len("c12".to_string(), Ty::VARCHAR, 4));
  // columns.push(Column::new_with_len("c13".to_string(), Ty::CHAR, 4));

  Schema::new(columns)
}

pub fn fill_vector_block(rowblock: &mut RowBlock) {
  for i in (0..1024) {
    rowblock.put_int1(1, i, (i % (i8::MAX - 1) as usize) as i8);
    rowblock.put_int2(2, i, (i % (i16::MAX -1) as usize) as i16);
    rowblock.put_int4(3, i, i as i32);
    rowblock.put_int8(4, i, i as i64);
    rowblock.put_float4(5, i, i as f32);
    rowblock.put_float8(6, i, i as f64);
    rowblock.put_date(7, i, i as i32);
    rowblock.put_time(8, i, i as i64);
    rowblock.put_timestamp(9, i, i as i64);

    rowblock.put_text(10, i, &"Rust");
  }
}

#[test]
fn test_FieldEval() {
  let schema = make_test_schema();

  let mut field: Box<MapEval> = Box::new(Field::new(&Column::new("c3".to_string(), Ty::Int4)));
  let mut r: Box<RowBlock> = Box::new(AllocatedVecRowBlock::new(schema.clone()));
  fill_vector_block(&mut *r);

  assert!(field.bind(&schema).is_ok());
  let v: &Vector = field.eval(&*r);
  let array: &[INT4_T] = as_array(v);

  assert_eq!(Ty::Int4, v.data_ty().ty());
  assert_eq!(1024, array.iter().count());
}<|endoftext|>