<commit_before>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// TODO: convert u32 to usize

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
#[derive(Clone)]
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece in its file.
    file_offset : u32,
    /// The length of the text in this Piece.
    length : u32,
    /// The logical offset of the Piece.
    logical_offset : u32,
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}:{} ({}:{})", self.file, self.file_offset, self.logical_offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    pieces : Vec<Piece>,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        // This has to be O(N) for the time being unless we want
        // to update all logical offsets when the table changes.
        // On modern hardware this will hardly be a bottleneck,
        // but we'll see.
        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }

        None
    }

    /// Update the logical offsets starting at a certain index.
    fn update_offsets(&mut self, start_index : usize) {
        // Don't do anything if this is the last index
        if start_index == self.piece_table.len() - 1 {
            return;
        }

        let mut offset = self.piece_table[start_index].logical_offset +
                         self.piece_table[start_index].length;

        for index in start_index + 1 .. self.piece_table.len() {
            let piece = &mut self.piece_table[index];
            piece.logical_offset = offset;
            offset += piece.length;
        }
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            file_offset : 0,
            length : size as u32,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let mut piece = Piece {
            file   : SourceFile::Append,
            file_offset : append_offset,
            logical_offset : 0, // Unknown right now
            length,
        };

        let action = Action {
            op     : Operation::Insert,
            pieces : Vec::new(),
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            self.update_offsets(0);
            return;
        }
        else if offset + length == self.length {
            piece.logical_offset = self.length - length;
            self.piece_table.push(piece);
            // No need to update offsets, this is the last piece
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return // TODO: Handle this better
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.logical_offset;
        let upper_size  = (split_piece.logical_offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset + lower_size,
                length         : upper_size,
                logical_offset : split_piece.logical_offset + lower_size + length,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset,
                length         : lower_size,
                logical_offset : split_piece.logical_offset,
            });
        }
        self.update_offsets(split_index);
    }

    /// Delete some text.
    pub fn delete(&mut self, offset : u32, length : u32) {
        let start_offset = offset;
        let end_offset   = offset + length;
        let start_index  = self.get_at_offset(start_offset).unwrap();
        let end_index    = self.get_at_offset(end_offset).unwrap();
        let delete_size  = (end_index - start_index) as u32;
        let num_pieces   = (end_index - start_index) + 1;

        let mut action = Action {
            length,
            offset,
            op     : Operation::Delete,
            pieces : Vec::new()
        };

        // Deletes can affect multiple pieces if the user wants to delete
        // across piece boundaries. We have to start at the bottom index
        // and move up. The code below doesn't result in a net positive number
        // of pieces in the piece table. We do any deletion necessary in a second
        // pass.
        for index in start_index .. end_index + 1 {
            let piece              = self.piece_table[index].clone();
            let piece_start_offset = piece.logical_offset;
            let piece_end_offset   = piece.logical_offset + piece.length;

            // Edge case : delete is embedded WITHIN a single piece
            if start_offset > piece_start_offset && end_offset < piece_end_offset {
                self.piece_table.remove(index);
                let upper_size = piece_end_offset - end_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : delete_size,
                    logical_offset : start_offset,
                });

                // We insert the upper part first
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size + delete_size,
                    length         : upper_size,
                    logical_offset : start_offset,
                });

                // Then the lower part
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset,
                    length         : lower_size,
                    logical_offset : piece.logical_offset,
                });
                break
            }

            // The deletion area starts in this piece and goes on to another
            if start_offset > piece_start_offset && end_offset >= piece_end_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - start_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : upper_size,
                    logical_offset : piece_start_offset + lower_size,
                });

                piece.length = lower_size;
                continue;
            }

            // The deletion area finishes in this piece
            if start_offset < piece_start_offset && end_offset <= piece_end_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - end_offset;
                let lower_size = end_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : lower_size,
                    logical_offset : piece_start_offset - lower_size,
                });

                piece.length = upper_size;
                continue;
            }

            // The deletion area is outside the bounds of this piece
            if start_offset <= piece_start_offset && end_offset >= piece_end_offset {
                let piece = &mut self.piece_table[index];
                action.pieces.push(piece.clone());
                piece.length = 0;
            }
        }

        // It's possible that we left zero-length pieces above. We should delete them.
        self.piece_table.retain(|ref v| v.length > 0);

        self.update_offsets(start_index);
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("foo", 0);
        file.insert("bar", 0);

        assert_eq!(file.length, 6);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.file_offset, 3);
        assert_eq!(first_element.logical_offset, 0);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.file_offset, 0);
        assert_eq!(second_element.logical_offset, 3);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);

        // TODO: Check the action's steps
    }

    #[test]
    fn it_inserts_inside_piece() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("aa", 0);
        file.insert("b", 1);

        assert_eq!(file.length, 3);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 3);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];
        let third_element  = &piece_table[2];

        assert_eq!(first_element.file_offset, 0);
        assert_eq!(first_element.logical_offset, 0);
        assert_eq!(first_element.length, 1);

        assert_eq!(second_element.file_offset, 2);
        assert_eq!(second_element.logical_offset, 1);
        assert_eq!(second_element.length, 1);

        assert_eq!(third_element.file_offset, 1);
        assert_eq!(third_element.logical_offset, 2);
        assert_eq!(third_element.length, 1);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);

        // TODO: Check the action's steps
    }

    #[test]
    fn it_deletes_inside_piece() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        // Test a delete that occurs inside a piece
        file.insert("foo", 0);
        file.delete(1, 1);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 1);
        assert_eq!(piece_table[1].length, 1);

        // TODO: check the action's steps
    }

    #[test]
    fn it_deletes_across_two_pieces() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("bar", 0);
        file.insert("foo", 0);
        file.delete(2,2);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 2);
        assert_eq!(piece_table[1].length, 2);

        // TODO: check the action's steps
    }

    #[test]
    fn it_deletes_across_three_pieces() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("cc", 0);
        file.insert("bb", 0);
        file.insert("aa", 0);
        file.delete(1, 4);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        // TODO: check the action's steps
    }
}
<commit_msg>fix(PieceFile): fix small bugs<commit_after>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// TODO: convert u32 to usize

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
#[derive(Clone)]
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece in its file.
    file_offset : u32,
    /// The length of the text in this Piece.
    length : u32,
    /// The logical offset of the Piece.
    logical_offset : u32,
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}:{} ({}:{})", self.file, self.file_offset, self.logical_offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    pieces : Vec<Piece>,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        // This has to be O(N) for the time being unless we want
        // to update all logical offsets when the table changes.
        // On modern hardware this will hardly be a bottleneck,
        // but we'll see.
        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }

        None
    }

    /// Update the logical offsets starting at a certain index.
    fn update_offsets(&mut self, start_index : usize) {
        // Don't do anything if this is the last index
        if start_index == self.piece_table.len() - 1 {
            return;
        }

        let mut offset = self.piece_table[start_index].logical_offset +
                         self.piece_table[start_index].length;

        for index in start_index + 1 .. self.piece_table.len() {
            let piece = &mut self.piece_table[index];
            piece.logical_offset = offset;
            offset += piece.length;
        }
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            file_offset : 0,
            length : size as u32,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let mut piece = Piece {
            file   : SourceFile::Append,
            file_offset : append_offset,
            logical_offset : 0, // Unknown right now
            length,
        };

        let action = Action {
            op     : Operation::Insert,
            pieces : Vec::new(),
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            self.update_offsets(0);
            return;
        }
        else if offset + length == self.length {
            piece.logical_offset = self.length - length;
            self.piece_table.push(piece);
            // No need to update offsets, this is the last piece
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return // TODO: Handle this better
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.logical_offset;
        let upper_size  = (split_piece.logical_offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset + lower_size,
                length         : upper_size,
                logical_offset : split_piece.logical_offset + lower_size + length,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset,
                length         : lower_size,
                logical_offset : split_piece.logical_offset,
            });
        }
        self.update_offsets(split_index);
    }

    /// Delete some text.
    pub fn delete(&mut self, offset : u32, length : u32) {
        let start_offset = offset;
        let end_offset   = offset + length;
        let start_index  = self.get_at_offset(start_offset).unwrap();
        let end_index    = self.get_at_offset(end_offset).unwrap();
        let delete_size  = ((end_index - start_index) as u32) + 1;
        let num_pieces   = (end_index - start_index) + 1;

        let mut action = Action {
            length,
            offset,
            op     : Operation::Delete,
            pieces : Vec::new()
        };

        // TODO: ensure we don't overflow
        self.length -= length;

        // Deletes can affect multiple pieces if the user wants to delete
        // across piece boundaries. We have to start at the bottom index
        // and move up. The code below doesn't result in a net positive number
        // of pieces in the piece table. We do any deletion necessary in a second
        // pass.
        for index in start_index .. end_index + 1 {
            let piece              = self.piece_table[index].clone();
            let piece_start_offset = piece.logical_offset;
            let piece_end_offset   = piece.logical_offset + piece.length;

            // Edge case : delete is embedded WITHIN a single piece
            if start_offset > piece_start_offset && end_offset < piece_end_offset {
                self.piece_table.remove(index);
                let upper_size = piece_end_offset - end_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : delete_size,
                    logical_offset : start_offset,
                });

                // We insert the upper part first
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size + delete_size,
                    length         : upper_size,
                    logical_offset : start_offset,
                });

                // Then the lower part
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset,
                    length         : lower_size,
                    logical_offset : piece.logical_offset,
                });
                break
            }

            // The deletion area starts in this piece and goes on to another
            if start_offset > piece_start_offset && end_offset >= piece_end_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - start_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : upper_size,
                    logical_offset : piece_start_offset + lower_size,
                });

                piece.length = lower_size;
                continue;
            }

            // The deletion area finishes in this piece
            if start_offset < piece_start_offset && end_offset <= piece_end_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - end_offset;
                let lower_size = end_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : lower_size,
                    logical_offset : piece_start_offset - lower_size,
                });

                piece.file_offset += lower_size;
                piece.length       = upper_size;
                continue;
            }

            // The deletion area is outside the bounds of this piece
            if start_offset <= piece_start_offset && end_offset >= piece_end_offset {
                let piece = &mut self.piece_table[index];
                action.pieces.push(piece.clone());
                piece.length = 0;
            }
        }

        self.actions.push(action);

        // It's possible that we left zero-length pieces above. We should delete them.
        self.piece_table.retain(|ref v| v.length > 0);

        self.update_offsets(start_index);
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("foo", 0);
        file.insert("bar", 0);

        assert_eq!(file.length, 6);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.file_offset, 3);
        assert_eq!(first_element.logical_offset, 0);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.file_offset, 0);
        assert_eq!(second_element.logical_offset, 3);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);
        assert_eq!(action.length, 3);
        assert_eq!(action.offset, 0);
    }

    #[test]
    fn it_inserts_inside_piece() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("aa", 0);
        file.insert("b", 1);

        assert_eq!(file.length, 3);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 3);

        let first_piece  = &piece_table[0];
        let second_piece = &piece_table[1];
        let third_piece  = &piece_table[2];

        assert_eq!(first_piece.file_offset, 0);
        assert_eq!(first_piece.logical_offset, 0);
        assert_eq!(first_piece.length, 1);

        assert_eq!(second_piece.file_offset, 2);
        assert_eq!(second_piece.logical_offset, 1);
        assert_eq!(second_piece.length, 1);

        assert_eq!(third_piece.file_offset, 1);
        assert_eq!(third_piece.logical_offset, 2);
        assert_eq!(third_piece.length, 1);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);
        assert_eq!(action.length, 2);
        assert_eq!(action.offset, 0);
    }

    #[test]
    fn it_deletes_inside_piece() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        // Test a delete that occurs inside a piece
        file.insert("foo", 0);
        file.delete(1, 1);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 1);
        assert_eq!(piece_table[1].length, 1);

        let action = &file.actions[1];
        assert_eq!(action.op, Operation::Delete);
        assert_eq!(action.length, 1);
        assert_eq!(action.offset, 1);

        let piece = &action.pieces[0];
        assert_eq!(piece.file, SourceFile::Append);
        assert_eq!(piece.length, 1);
        assert_eq!(piece.file_offset, 1);
        assert_eq!(piece.logical_offset, 1);
    }

    #[test]
    fn it_deletes_across_two_pieces() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("bar", 0);
        file.insert("foo", 0);
        file.delete(2,2);

        assert_eq!(file.length, 4);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 2);
        assert_eq!(piece_table[1].length, 2);

        // TODO: check the action's steps
    }

    #[test]
    fn it_deletes_across_three_pieces() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("cc", 0);
        file.insert("bb", 0);
        file.insert("aa", 0);
        file.delete(1, 4);

        assert_eq!(file.length, 2);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_piece  = &piece_table[0];
        let second_piece = &piece_table[1];

        assert_eq!(first_piece.file_offset, 4);
        assert_eq!(first_piece.logical_offset, 0);
        assert_eq!(first_piece.length, 1);

        assert_eq!(second_piece.file_offset, 1);
        assert_eq!(second_piece.logical_offset, 1);
        assert_eq!(second_piece.length, 1);

        // TODO: check the action's steps
    }
}
<|endoftext|>


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

use std::ptr;
use std::sync::Arc;
use std::time::Duration;

use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend, Stream};
use grpc_sys;

use async::{BatchFuture, BatchMessage, BatchType, CqFuture, SpinLock};
use call::{check_run, Call, Method};
use channel::Channel;
use codec::{DeserializeFn, SerializeFn};
use error::{Error, Result};
use super::{ShareCall, ShareCallHolder, SinkBase, WriteFlags};

/// Update the flag bit in res.
#[inline]
pub fn change_flag(res: &mut u32, flag: u32, set: bool) {
    if set {
        *res |= flag;
    } else {
        *res &= !flag;
    }
}

#[derive(Default)]
pub struct CallOption {
    timeout: Option<Duration>,
    write_flags: WriteFlags,
    call_flags: u32,
}

impl CallOption {
    /// Signal that the call is idempotent
    pub fn idempotent(mut self, is_idempotent: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST,
            is_idempotent,
        );
        self
    }

    /// Signal that the call should not return UNAVAILABLE before it has started
    pub fn wait_for_ready(mut self, wait_for_ready: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_WAIT_FOR_READY,
            wait_for_ready,
        );
        self
    }

    /// Signal that the call is cacheable. GRPC is free to use GET verb
    pub fn cacheable(mut self, cacheable: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_CACHEABLE_REQUEST,
            cacheable,
        );
        self
    }

    pub fn write_flags(mut self, write_flags: WriteFlags) -> CallOption {
        self.write_flags = write_flags;
        self
    }

    /// Set a timeout.
    pub fn timeout(mut self, timeout: Duration) -> CallOption {
        self.timeout = Some(timeout);
        self
    }

    /// Get the timeout.
    pub fn get_timeout(&self) -> Option<Duration> {
        self.timeout
    }
}

impl Call {
    pub fn unary_async<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        req: &P,
        opt: CallOption,
    ) -> Result<ClientUnaryReceiver<Q>> {
        let call = channel.create_call(method, &opt)?;
        let mut payload = vec![];
        (method.req_ser())(req, &mut payload);
        let cq_f = check_run(BatchType::CheckRead, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_unary(
                call.call,
                ctx,
                payload.as_ptr() as *const _,
                payload.len(),
                opt.write_flags.flags,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });
        Ok(ClientUnaryReceiver::new(call, cq_f, method.resp_de()))
    }

    pub fn client_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        opt: CallOption,
    ) -> Result<(ClientCStreamSender<P>, ClientCStreamReceiver<Q>)> {
        let call = channel.create_call(method, &opt)?;
        let cq_f = check_run(BatchType::CheckRead, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_client_streaming(
                call.call,
                ctx,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        let share_call = Arc::new(SpinLock::new(ShareCall::new(call, cq_f)));
        let sink = ClientCStreamSender::new(share_call.clone(), method.req_ser());
        let recv = ClientCStreamReceiver {
            call: share_call,
            resp_de: method.resp_de(),
        };
        Ok((sink, recv))
    }

    pub fn server_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        req: &P,
        opt: CallOption,
    ) -> Result<ClientSStreamReceiver<Q>> {
        let call = channel.create_call(method, &opt)?;
        let mut payload = vec![];
        (method.req_ser())(req, &mut payload);
        let cq_f = check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_server_streaming(
                call.call,
                ctx,
                payload.as_ptr() as _,
                payload.len(),
                opt.write_flags.flags,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        // TODO: handle header
        check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_recv_initial_metadata(call.call, ctx, tag)
        });

        Ok(ClientSStreamReceiver::new(call, cq_f, method.resp_de()))
    }

    pub fn duplex_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        opt: CallOption,
    ) -> Result<(ClientDuplexSender<P>, ClientDuplexReceiver<Q>)> {
        let call = channel.create_call(method, &opt)?;
        let cq_f = check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_duplex_streaming(
                call.call,
                ctx,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        // TODO: handle header.
        check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_recv_initial_metadata(call.call, ctx, tag)
        });

        let share_call = Arc::new(SpinLock::new(ShareCall::new(call, cq_f)));
        let sink = ClientDuplexSender::new(share_call.clone(), method.req_ser());
        let recv = ClientDuplexReceiver::new(share_call, method.resp_de());
        Ok((sink, recv))
    }
}

/// A receiver for unary request.
///
/// The future is resolved once response is received.
pub struct ClientUnaryReceiver<T> {
    call: Call,
    resp_f: CqFuture<BatchMessage>,
    resp_de: DeserializeFn<T>,
}

impl<T> ClientUnaryReceiver<T> {
    fn new(
        call: Call,
        resp_f: CqFuture<BatchMessage>,
        de: DeserializeFn<T>,
    ) -> ClientUnaryReceiver<T> {
        ClientUnaryReceiver {
            call: call,
            resp_f: resp_f,
            resp_de: de,
        }
    }

    /// Cancel the call.
    pub fn cancel(&mut self) {
        self.call.cancel()
    }
}

impl<T> Future for ClientUnaryReceiver<T> {
    type Item = T;
    type Error = Error;

    fn poll(&mut self) -> Poll<T, Error> {
        let data = try_ready!(self.resp_f.poll());
        let t = (self.resp_de)(&data.unwrap())?;
        Ok(Async::Ready(t))
    }
}

/// A receiver for client streaming call.
pub struct ClientCStreamReceiver<T> {
    call: Arc<SpinLock<ShareCall>>,
    resp_de: DeserializeFn<T>,
}

impl<T> ClientCStreamReceiver<T> {
    /// Cancel the call.
    pub fn cancel(&mut self) {
        let lock = self.call.lock();
        lock.call.cancel()
    }
}

impl<T> Future for ClientCStreamReceiver<T> {
    type Item = T;
    type Error = Error;

    fn poll(&mut self) -> Poll<T, Error> {
        let data = {
            let mut call = self.call.lock();
            try_ready!(call.poll_finish())
        };
        let t = (self.resp_de)(&data.unwrap())?;
        Ok(Async::Ready(t))
    }
}

/// A sink for client streaming call and duplex streaming call.
pub struct StreamingCallSink<P> {
    call: Arc<SpinLock<ShareCall>>,
    sink_base: SinkBase,
    close_f: Option<BatchFuture>,
    req_ser: SerializeFn<P>,
}

impl<P> StreamingCallSink<P> {
    fn new(call: Arc<SpinLock<ShareCall>>, ser: SerializeFn<P>) -> StreamingCallSink<P> {
        StreamingCallSink {
            call: call,
            sink_base: SinkBase::new(false),
            close_f: None,
            req_ser: ser,
        }
    }

    pub fn cancel(&mut self) {
        let call = self.call.lock();
        call.call.cancel()
    }
}

impl<P> Sink for StreamingCallSink<P> {
    type SinkItem = (P, WriteFlags);
    type SinkError = Error;

    fn start_send(&mut self, (msg, flags): Self::SinkItem) -> StartSend<Self::SinkItem, Error> {
        {
            let mut call = self.call.lock();
            call.check_alive()?;
        }
        self.sink_base
            .start_send(&mut self.call, &msg, flags, self.req_ser)
            .map(|s| if s {
                AsyncSink::Ready
            } else {
                AsyncSink::NotReady((msg, flags))
            })
    }

    fn poll_complete(&mut self) -> Poll<(), Error> {
        {
            let mut call = self.call.lock();
            call.check_alive()?;
        }
        self.sink_base.poll_complete()
    }

    fn close(&mut self) -> Poll<(), Error> {
        let mut call = self.call.lock();
        if self.close_f.is_none() {
            try_ready!(self.sink_base.poll_complete());

            let close_f = call.call.start_send_close_client()?;
            self.close_f = Some(close_f);
        }

        if let Async::NotReady = self.close_f.as_mut().unwrap().poll()? {
            // if call is finished, can return early here.
            call.check_alive()?;
            return Ok(Async::NotReady);
        }
        Ok(Async::Ready(()))
    }
}

pub type ClientCStreamSender<T> = StreamingCallSink<T>;
pub type ClientDuplexSender<T> = StreamingCallSink<T>;

struct ResponseStreamImpl<H, T> {
    call: H,
    msg_f: Option<BatchFuture>,
    read_done: bool,
    resp_de: DeserializeFn<T>,
}

impl<H: ShareCallHolder, T> ResponseStreamImpl<H, T> {
    fn new(call: H, resp_de: DeserializeFn<T>) -> ResponseStreamImpl<H, T> {
        ResponseStreamImpl {
            call: call,
            msg_f: None,
            read_done: false,
            resp_de: resp_de,
        }
    }

    fn cancel(&mut self) {
        self.call.call(|c| c.call.cancel())
    }

    fn poll(&mut self) -> Poll<Option<T>, Error> {
        let mut finished = false;
        self.call.call(|c| {
            if c.finished {
                finished = true;
                return Ok(());
            }

            let res = c.poll_finish().map(|_| ());
            finished = c.finished;
            res
        })?;

        let mut bytes = None;
        loop {
            if !self.read_done {
                if let Some(ref mut msg_f) = self.msg_f {
                    bytes = try_ready!(msg_f.poll());
                    if bytes.is_none() {
                        self.read_done = true;
                    }
                }
            }

            if self.read_done {
                if finished {
                    return Ok(Async::Ready(None));
                }
                return Ok(Async::NotReady);
            }

            // so msg_f must be either stale or not initialised yet.
            self.msg_f.take();
            let msg_f = self.call.call(|c| c.call.start_recv_message())?;
            self.msg_f = Some(msg_f);
            if let Some(ref data) = bytes {
                let msg = (self.resp_de)(data)?;
                return Ok(Async::Ready(Some(msg)));
            }
        }
    }
}

/// A receiver for server streaming call.
pub struct ClientSStreamReceiver<Q> {
    imp: ResponseStreamImpl<ShareCall, Q>,
}

impl<Q> ClientSStreamReceiver<Q> {
    fn new(
        call: Call,
        finish_f: CqFuture<BatchMessage>,
        de: DeserializeFn<Q>,
    ) -> ClientSStreamReceiver<Q> {
        let share_call = ShareCall::new(call, finish_f);
        ClientSStreamReceiver {
            imp: ResponseStreamImpl::new(share_call, de),
        }
    }

    pub fn cancel(&mut self) {
        self.imp.cancel()
    }
}

impl<Q> Stream for ClientSStreamReceiver<Q> {
    type Item = Q;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Q>, Error> {
        self.imp.poll()
    }
}

/// A response receiver for duplex call.
pub struct ClientDuplexReceiver<Q> {
    imp: ResponseStreamImpl<Arc<SpinLock<ShareCall>>, Q>,
}

impl<Q> ClientDuplexReceiver<Q> {
    fn new(call: Arc<SpinLock<ShareCall>>, de: DeserializeFn<Q>) -> ClientDuplexReceiver<Q> {
        ClientDuplexReceiver {
            imp: ResponseStreamImpl::new(call, de),
        }
    }

    pub fn cancel(&mut self) {
        self.imp.cancel()
    }
}

impl<Q> Stream for ClientDuplexReceiver<Q> {
    type Item = Q;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Q>, Error> {
        self.imp.poll()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_change_flag() {
        let mut flag = 2 | 4;
        super::change_flag(&mut flag, 8, true);
        assert_eq!(flag, 2 | 4 | 8);
        super::change_flag(&mut flag, 4, false);
        assert_eq!(flag, 2 | 8);
    }
}
<commit_msg>CallOptions is Clone (#143)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ptr;
use std::sync::Arc;
use std::time::Duration;

use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend, Stream};
use grpc_sys;

use async::{BatchFuture, BatchMessage, BatchType, CqFuture, SpinLock};
use call::{check_run, Call, Method};
use channel::Channel;
use codec::{DeserializeFn, SerializeFn};
use error::{Error, Result};
use super::{ShareCall, ShareCallHolder, SinkBase, WriteFlags};

/// Update the flag bit in res.
#[inline]
pub fn change_flag(res: &mut u32, flag: u32, set: bool) {
    if set {
        *res |= flag;
    } else {
        *res &= !flag;
    }
}

#[derive(Clone, Default)]
pub struct CallOption {
    timeout: Option<Duration>,
    write_flags: WriteFlags,
    call_flags: u32,
}

impl CallOption {
    /// Signal that the call is idempotent
    pub fn idempotent(mut self, is_idempotent: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST,
            is_idempotent,
        );
        self
    }

    /// Signal that the call should not return UNAVAILABLE before it has started
    pub fn wait_for_ready(mut self, wait_for_ready: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_WAIT_FOR_READY,
            wait_for_ready,
        );
        self
    }

    /// Signal that the call is cacheable. GRPC is free to use GET verb
    pub fn cacheable(mut self, cacheable: bool) -> CallOption {
        change_flag(
            &mut self.call_flags,
            grpc_sys::GRPC_INITIAL_METADATA_CACHEABLE_REQUEST,
            cacheable,
        );
        self
    }

    pub fn write_flags(mut self, write_flags: WriteFlags) -> CallOption {
        self.write_flags = write_flags;
        self
    }

    /// Set a timeout.
    pub fn timeout(mut self, timeout: Duration) -> CallOption {
        self.timeout = Some(timeout);
        self
    }

    /// Get the timeout.
    pub fn get_timeout(&self) -> Option<Duration> {
        self.timeout
    }
}

impl Call {
    pub fn unary_async<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        req: &P,
        opt: CallOption,
    ) -> Result<ClientUnaryReceiver<Q>> {
        let call = channel.create_call(method, &opt)?;
        let mut payload = vec![];
        (method.req_ser())(req, &mut payload);
        let cq_f = check_run(BatchType::CheckRead, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_unary(
                call.call,
                ctx,
                payload.as_ptr() as *const _,
                payload.len(),
                opt.write_flags.flags,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });
        Ok(ClientUnaryReceiver::new(call, cq_f, method.resp_de()))
    }

    pub fn client_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        opt: CallOption,
    ) -> Result<(ClientCStreamSender<P>, ClientCStreamReceiver<Q>)> {
        let call = channel.create_call(method, &opt)?;
        let cq_f = check_run(BatchType::CheckRead, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_client_streaming(
                call.call,
                ctx,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        let share_call = Arc::new(SpinLock::new(ShareCall::new(call, cq_f)));
        let sink = ClientCStreamSender::new(share_call.clone(), method.req_ser());
        let recv = ClientCStreamReceiver {
            call: share_call,
            resp_de: method.resp_de(),
        };
        Ok((sink, recv))
    }

    pub fn server_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        req: &P,
        opt: CallOption,
    ) -> Result<ClientSStreamReceiver<Q>> {
        let call = channel.create_call(method, &opt)?;
        let mut payload = vec![];
        (method.req_ser())(req, &mut payload);
        let cq_f = check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_server_streaming(
                call.call,
                ctx,
                payload.as_ptr() as _,
                payload.len(),
                opt.write_flags.flags,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        // TODO: handle header
        check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_recv_initial_metadata(call.call, ctx, tag)
        });

        Ok(ClientSStreamReceiver::new(call, cq_f, method.resp_de()))
    }

    pub fn duplex_streaming<P, Q>(
        channel: &Channel,
        method: &Method<P, Q>,
        opt: CallOption,
    ) -> Result<(ClientDuplexSender<P>, ClientDuplexReceiver<Q>)> {
        let call = channel.create_call(method, &opt)?;
        let cq_f = check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_start_duplex_streaming(
                call.call,
                ctx,
                ptr::null_mut(),
                opt.call_flags,
                tag,
            )
        });

        // TODO: handle header.
        check_run(BatchType::Finish, |ctx, tag| unsafe {
            grpc_sys::grpcwrap_call_recv_initial_metadata(call.call, ctx, tag)
        });

        let share_call = Arc::new(SpinLock::new(ShareCall::new(call, cq_f)));
        let sink = ClientDuplexSender::new(share_call.clone(), method.req_ser());
        let recv = ClientDuplexReceiver::new(share_call, method.resp_de());
        Ok((sink, recv))
    }
}

/// A receiver for unary request.
///
/// The future is resolved once response is received.
pub struct ClientUnaryReceiver<T> {
    call: Call,
    resp_f: CqFuture<BatchMessage>,
    resp_de: DeserializeFn<T>,
}

impl<T> ClientUnaryReceiver<T> {
    fn new(
        call: Call,
        resp_f: CqFuture<BatchMessage>,
        de: DeserializeFn<T>,
    ) -> ClientUnaryReceiver<T> {
        ClientUnaryReceiver {
            call: call,
            resp_f: resp_f,
            resp_de: de,
        }
    }

    /// Cancel the call.
    pub fn cancel(&mut self) {
        self.call.cancel()
    }
}

impl<T> Future for ClientUnaryReceiver<T> {
    type Item = T;
    type Error = Error;

    fn poll(&mut self) -> Poll<T, Error> {
        let data = try_ready!(self.resp_f.poll());
        let t = (self.resp_de)(&data.unwrap())?;
        Ok(Async::Ready(t))
    }
}

/// A receiver for client streaming call.
pub struct ClientCStreamReceiver<T> {
    call: Arc<SpinLock<ShareCall>>,
    resp_de: DeserializeFn<T>,
}

impl<T> ClientCStreamReceiver<T> {
    /// Cancel the call.
    pub fn cancel(&mut self) {
        let lock = self.call.lock();
        lock.call.cancel()
    }
}

impl<T> Future for ClientCStreamReceiver<T> {
    type Item = T;
    type Error = Error;

    fn poll(&mut self) -> Poll<T, Error> {
        let data = {
            let mut call = self.call.lock();
            try_ready!(call.poll_finish())
        };
        let t = (self.resp_de)(&data.unwrap())?;
        Ok(Async::Ready(t))
    }
}

/// A sink for client streaming call and duplex streaming call.
pub struct StreamingCallSink<P> {
    call: Arc<SpinLock<ShareCall>>,
    sink_base: SinkBase,
    close_f: Option<BatchFuture>,
    req_ser: SerializeFn<P>,
}

impl<P> StreamingCallSink<P> {
    fn new(call: Arc<SpinLock<ShareCall>>, ser: SerializeFn<P>) -> StreamingCallSink<P> {
        StreamingCallSink {
            call: call,
            sink_base: SinkBase::new(false),
            close_f: None,
            req_ser: ser,
        }
    }

    pub fn cancel(&mut self) {
        let call = self.call.lock();
        call.call.cancel()
    }
}

impl<P> Sink for StreamingCallSink<P> {
    type SinkItem = (P, WriteFlags);
    type SinkError = Error;

    fn start_send(&mut self, (msg, flags): Self::SinkItem) -> StartSend<Self::SinkItem, Error> {
        {
            let mut call = self.call.lock();
            call.check_alive()?;
        }
        self.sink_base
            .start_send(&mut self.call, &msg, flags, self.req_ser)
            .map(|s| if s {
                AsyncSink::Ready
            } else {
                AsyncSink::NotReady((msg, flags))
            })
    }

    fn poll_complete(&mut self) -> Poll<(), Error> {
        {
            let mut call = self.call.lock();
            call.check_alive()?;
        }
        self.sink_base.poll_complete()
    }

    fn close(&mut self) -> Poll<(), Error> {
        let mut call = self.call.lock();
        if self.close_f.is_none() {
            try_ready!(self.sink_base.poll_complete());

            let close_f = call.call.start_send_close_client()?;
            self.close_f = Some(close_f);
        }

        if let Async::NotReady = self.close_f.as_mut().unwrap().poll()? {
            // if call is finished, can return early here.
            call.check_alive()?;
            return Ok(Async::NotReady);
        }
        Ok(Async::Ready(()))
    }
}

pub type ClientCStreamSender<T> = StreamingCallSink<T>;
pub type ClientDuplexSender<T> = StreamingCallSink<T>;

struct ResponseStreamImpl<H, T> {
    call: H,
    msg_f: Option<BatchFuture>,
    read_done: bool,
    resp_de: DeserializeFn<T>,
}

impl<H: ShareCallHolder, T> ResponseStreamImpl<H, T> {
    fn new(call: H, resp_de: DeserializeFn<T>) -> ResponseStreamImpl<H, T> {
        ResponseStreamImpl {
            call: call,
            msg_f: None,
            read_done: false,
            resp_de: resp_de,
        }
    }

    fn cancel(&mut self) {
        self.call.call(|c| c.call.cancel())
    }

    fn poll(&mut self) -> Poll<Option<T>, Error> {
        let mut finished = false;
        self.call.call(|c| {
            if c.finished {
                finished = true;
                return Ok(());
            }

            let res = c.poll_finish().map(|_| ());
            finished = c.finished;
            res
        })?;

        let mut bytes = None;
        loop {
            if !self.read_done {
                if let Some(ref mut msg_f) = self.msg_f {
                    bytes = try_ready!(msg_f.poll());
                    if bytes.is_none() {
                        self.read_done = true;
                    }
                }
            }

            if self.read_done {
                if finished {
                    return Ok(Async::Ready(None));
                }
                return Ok(Async::NotReady);
            }

            // so msg_f must be either stale or not initialised yet.
            self.msg_f.take();
            let msg_f = self.call.call(|c| c.call.start_recv_message())?;
            self.msg_f = Some(msg_f);
            if let Some(ref data) = bytes {
                let msg = (self.resp_de)(data)?;
                return Ok(Async::Ready(Some(msg)));
            }
        }
    }
}

/// A receiver for server streaming call.
pub struct ClientSStreamReceiver<Q> {
    imp: ResponseStreamImpl<ShareCall, Q>,
}

impl<Q> ClientSStreamReceiver<Q> {
    fn new(
        call: Call,
        finish_f: CqFuture<BatchMessage>,
        de: DeserializeFn<Q>,
    ) -> ClientSStreamReceiver<Q> {
        let share_call = ShareCall::new(call, finish_f);
        ClientSStreamReceiver {
            imp: ResponseStreamImpl::new(share_call, de),
        }
    }

    pub fn cancel(&mut self) {
        self.imp.cancel()
    }
}

impl<Q> Stream for ClientSStreamReceiver<Q> {
    type Item = Q;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Q>, Error> {
        self.imp.poll()
    }
}

/// A response receiver for duplex call.
pub struct ClientDuplexReceiver<Q> {
    imp: ResponseStreamImpl<Arc<SpinLock<ShareCall>>, Q>,
}

impl<Q> ClientDuplexReceiver<Q> {
    fn new(call: Arc<SpinLock<ShareCall>>, de: DeserializeFn<Q>) -> ClientDuplexReceiver<Q> {
        ClientDuplexReceiver {
            imp: ResponseStreamImpl::new(call, de),
        }
    }

    pub fn cancel(&mut self) {
        self.imp.cancel()
    }
}

impl<Q> Stream for ClientDuplexReceiver<Q> {
    type Item = Q;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Q>, Error> {
        self.imp.poll()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_change_flag() {
        let mut flag = 2 | 4;
        super::change_flag(&mut flag, 8, true);
        assert_eq!(flag, 2 | 4 | 8);
        super::change_flag(&mut flag, 4, false);
        assert_eq!(flag, 2 | 8);
    }
}
<|endoftext|>


<commit_before>extern crate cql_ffi;

use cass_error::CassError;
use cass_uuid::CassUuid;
use cass_value::CassValueType;
use cass_inet::CassInet;
use cass_string::CassString;
use cass_bytes::CassBytes;
use cass_decimal::CassDecimal;
use cass_iterator::CassIterator;

use std::mem;

pub use cql_ffi::CassColumnType;

pub struct CassColumn<'a> {
    pub column:&'a cql_ffi::CassValue
}

impl<'a> CassColumn<'a> {

    pub fn get_type(self) -> CassValueType {unsafe{
        cql_ffi::cass_value_type(self.column)
    }}

    pub fn collection_iter(self) -> CassIterator<'a> {unsafe{
        CassIterator{iterator:&mut*cql_ffi::cass_iterator_from_collection(&*self.column)}
    }}

    pub fn get_int32(self) -> Result<i32, CassError> {unsafe{
       assert!(self.get_type() == CassValueType::INT);
        let ref mut output = 0i32;
        match cql_ffi::cass_value_get_int32(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_int64(self) -> Result<i64, CassError> {unsafe{
       assert!(self.get_type() == CassValueType::BIGINT);
        let ref mut output = 0i64;
        match cql_ffi::cass_value_get_int64(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_float(self) -> Result<f32, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::FLOAT);
        let ref mut output = 0f32;
        match cql_ffi::cass_value_get_float(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_double(self) -> Result<f64, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::DOUBLE);
        let ref mut output = 0f64;
        match cql_ffi::cass_value_get_double(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_bool(self) -> Result<bool, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::BOOLEAN);
        let ref mut b_bln = 0u32;
        match cql_ffi::cass_value_get_bool(self.column,b_bln) {
            cql_ffi::CassError::CASS_OK => Ok(true),
            err => Err(CassError{error:err})
        }
    }}

    //FIXME this should emit a uuid::Uuid instead of a CassUuid
    pub fn get_uuid(self) -> Result<CassUuid, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_uuid(self.column,output) {
            cql_ffi::CassError::CASS_OK => {
                Ok(CassUuid{uuid:*output})
            },
            err => Err(CassError{error:err})
        }
    }}

    //FIXME this should emit a uuid::Uuid instead of a CassUuid
    pub fn get_inet(self) -> Result<CassInet, CassError> {unsafe{
        match self.get_inet() {
            Ok(inet) => Ok(inet),
            Err(err) => Err(err)
        }
    }}

    pub fn get_string(self) -> Result<CassString, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_string(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassString{string:*output}),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_bytes(self) -> Result<CassBytes, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_bytes(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassBytes{bytes:*output}),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_decimal(self) -> Result<CassDecimal, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_decimal(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassDecimal{decimal:*output}),
            err => Err(CassError{error:err})
        }
    }}

}
<commit_msg>more asininity<commit_after>extern crate cql_ffi;

use cass_error::CassError;
use cass_uuid::CassUuid;
use cass_value::CassValueType;
use cass_inet::CassInet;
use cass_string::CassString;
use cass_bytes::CassBytes;
use cass_decimal::CassDecimal;
use cass_iterator::CassIterator;

use std::mem;

pub use cql_ffi::CassColumnType;

pub struct CassColumn<'a> {
    pub column:&'a cql_ffi::CassValue
}

impl<'a> CassColumn<'a> {

    pub fn get_type(&self) -> CassValueType {unsafe{
        cql_ffi::cass_value_type(self.column)
    }}

    pub fn collection_iter(&self) -> CassIterator<'a> {unsafe{
        CassIterator{iterator:&mut*cql_ffi::cass_iterator_from_collection(&*self.column)}
    }}

    pub fn get_int32(&self) -> Result<i32, CassError> {unsafe{
       assert!(self.get_type() == CassValueType::INT);
        let ref mut output = 0i32;
        match cql_ffi::cass_value_get_int32(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_int64(&self) -> Result<i64, CassError> {unsafe{
       assert!(self.get_type() == CassValueType::BIGINT);
        let ref mut output = 0i64;
        match cql_ffi::cass_value_get_int64(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_float(&self) -> Result<f32, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::FLOAT);
        let ref mut output = 0f32;
        match cql_ffi::cass_value_get_float(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_double(&self) -> Result<f64, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::DOUBLE);
        let ref mut output = 0f64;
        match cql_ffi::cass_value_get_double(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(*output),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_bool(&self) -> Result<bool, CassError> {unsafe{
        assert!(self.get_type() == CassValueType::BOOLEAN);
        let ref mut b_bln = 0u32;
        match cql_ffi::cass_value_get_bool(self.column,b_bln) {
            cql_ffi::CassError::CASS_OK => Ok(true),
            err => Err(CassError{error:err})
        }
    }}

    //FIXME this should emit a uuid::Uuid instead of a CassUuid
    pub fn get_uuid(&self) -> Result<CassUuid, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_uuid(self.column,output) {
            cql_ffi::CassError::CASS_OK => {
                Ok(CassUuid{uuid:*output})
            },
            err => Err(CassError{error:err})
        }
    }}

    //FIXME this should emit a uuid::Uuid instead of a CassUuid
    pub fn get_inet(&self) -> Result<CassInet, CassError> {unsafe{
        match self.get_inet() {
            Ok(inet) => Ok(inet),
            Err(err) => Err(err)
        }
    }}

    pub fn get_string(&self) -> Result<CassString, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_string(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassString{string:*output}),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_bytes(&self) -> Result<CassBytes, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_bytes(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassBytes{bytes:*output}),
            err => Err(CassError{error:err})
        }
    }}

    pub fn get_decimal(self) -> Result<CassDecimal, CassError> {unsafe{
        let output =  mem::zeroed();
        match cql_ffi::cass_value_get_decimal(self.column,output) {
            cql_ffi::CassError::CASS_OK => Ok(CassDecimal{decimal:*output}),
            err => Err(CassError{error:err})
        }
    }}

}
<|endoftext|>


<commit_before>use na;
use shape::{FeatureId, Segment, SegmentPointLocation};
use query::{PointProjection, PointQuery, PointQueryWithLocation};
use math::{Isometry, Point};

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Segment<P> {
    #[inline]
    fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_location(m, pt, solid);
        projection
    }

    #[inline]
    fn project_point_with_feature(&self, m: &M, pt: &P) -> (PointProjection<P>, FeatureId) {
        let (proj, loc) = self.project_point_with_location(m, pt, false);
        let feature = match loc {
            SegmentPointLocation::OnVertex(i) => FeatureId::Vertex(i),
            SegmentPointLocation::OnEdge(..) => FeatureId::Edge(0),
        };

        (proj, feature)
    }

    // NOTE: the default implementation of `.distance_to_point(...)` will return the error that was
    // eaten by the `::approx_eq(...)` on `project_point(...)`.
}

impl<P: Point, M: Isometry<P>> PointQueryWithLocation<P, M> for Segment<P> {
    type Location = SegmentPointLocation<P::Real>;

    #[inline]
    fn project_point_with_location(
        &self,
        m: &M,
        pt: &P,
        _: bool,
    ) -> (PointProjection<P>, Self::Location) {
        let ls_pt = m.inverse_transform_point(pt);
        let ab = *self.b() - *self.a();
        let ap = ls_pt - *self.a();
        let ab_ap = na::dot(&ab, &ap);
        let sqnab = na::norm_squared(&ab);
        let _1 = na::one::<P::Real>();

        let mut proj;
        let location;

        if ab_ap <= na::zero() {
            // Voronoï region of vertex 'a'.
            location = SegmentPointLocation::OnVertex(0);
            proj = m.transform_point(self.a());
        } else if ab_ap >= sqnab {
            // Voronoï region of vertex 'b'.
            location = SegmentPointLocation::OnVertex(1);
            proj = m.transform_point(self.b());
        } else {
            assert!(sqnab != na::zero());

            // Voronoï region of the segment interior.
            let u = ab_ap / sqnab;
            let bcoords = [_1 - u, u];
            location = SegmentPointLocation::OnEdge(bcoords);
            proj = *self.a();
            proj.axpy(bcoords[1], self.b(), bcoords[0]);
            proj = m.transform_point(&proj);
        }

        // FIXME: is this acceptable?
        let inside = relative_eq!(proj, *pt);

        (PointProjection::new(inside, proj), location)
    }
}
<commit_msg>Fix 2D point/segment projection with feature.<commit_after>use math::{Isometry, Point};
use na;
use query::{PointProjection, PointQuery, PointQueryWithLocation};
use shape::{FeatureId, Segment, SegmentPointLocation};
use utils;

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Segment<P> {
    #[inline]
    fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_location(m, pt, solid);
        projection
    }

    #[inline]
    fn project_point_with_feature(&self, m: &M, pt: &P) -> (PointProjection<P>, FeatureId) {
        let (proj, loc) = self.project_point_with_location(m, pt, false);
        let feature = match loc {
            SegmentPointLocation::OnVertex(i) => FeatureId::Vertex(i),
            SegmentPointLocation::OnEdge(..) => {
                if na::dimension::<P::Vector>() == 2 {
                    let dir = self.scaled_direction();
                    let dpt = *pt - proj.point;
                    if utils::perp2(&dpt, &dir) >= na::zero() {
                        FeatureId::Face(0)
                    } else {
                        FeatureId::Face(1)
                    }
                } else {
                    FeatureId::Edge(0)
                }
            }
        };

        (proj, feature)
    }

    // NOTE: the default implementation of `.distance_to_point(...)` will return the error that was
    // eaten by the `::approx_eq(...)` on `project_point(...)`.
}

impl<P: Point, M: Isometry<P>> PointQueryWithLocation<P, M> for Segment<P> {
    type Location = SegmentPointLocation<P::Real>;

    #[inline]
    fn project_point_with_location(
        &self,
        m: &M,
        pt: &P,
        _: bool,
    ) -> (PointProjection<P>, Self::Location) {
        let ls_pt = m.inverse_transform_point(pt);
        let ab = *self.b() - *self.a();
        let ap = ls_pt - *self.a();
        let ab_ap = na::dot(&ab, &ap);
        let sqnab = na::norm_squared(&ab);
        let _1 = na::one::<P::Real>();

        let mut proj;
        let location;

        if ab_ap <= na::zero() {
            // Voronoï region of vertex 'a'.
            location = SegmentPointLocation::OnVertex(0);
            proj = m.transform_point(self.a());
        } else if ab_ap >= sqnab {
            // Voronoï region of vertex 'b'.
            location = SegmentPointLocation::OnVertex(1);
            proj = m.transform_point(self.b());
        } else {
            assert!(sqnab != na::zero());

            // Voronoï region of the segment interior.
            let u = ab_ap / sqnab;
            let bcoords = [_1 - u, u];
            location = SegmentPointLocation::OnEdge(bcoords);
            proj = *self.a();
            proj.axpy(bcoords[1], self.b(), bcoords[0]);
            proj = m.transform_point(&proj);
        }

        // FIXME: is this acceptable?
        let inside = relative_eq!(proj, *pt);

        (PointProjection::new(inside, proj), location)
    }
}
<|endoftext|>


<commit_before>use std::io;

use curl;
use curl::easy::{Easy, List};
use tokio_curl::Session;
use tokio_core::reactor::Handle;
use rustc_serialize::json::{self, Json};    // XXX: use serde
use futures::{Future, BoxFuture};
use futures::{finished, failed};

// HttpClient (service)
//
//  new(curl_session)
//
//  call(req: HttpRequest) -> Future<Response>

struct HttpJsonClient {
    session: Session,
}

impl HttpJsonClient {

    pub fn new(handle: Handle) -> HttpJsonClient {
        HttpJsonClient {
            session: Session::new(handle),
        }
    }

    pub fn perform(&self, req: JsonRequest, auth: Option<String>)
        -> BoxFuture<JsonResponse, io::Error>
    {
        let curl = match self.build(req, auth) {
            Ok(curl) => curl,
            Err(e) => {
                return failed(io::Error::new(
                    io::ErrorKind::Other, "Curl error"))
                    .boxed()
            }
        };

        self.session.perform(curl)
            .map_err(|e| e.into_error())
            .and_then(|resp| {
                // TODO: collect & parse response body
                finished(JsonResponse {})
            }).boxed()
    }

    fn build(&self, req: JsonRequest, auth: Option<String>)
        -> Result<Easy, curl::Error>
    {
        let mut curl = Easy::new();
        let mut headers = List::new();
        try!(curl.forbid_reuse(true));
        match req.data {
            Some(ref payload) => {
                try!(curl.post(true));
                try!(headers.append("Content-Type: application/json"));
                try!(curl.post_fields_copy(
                    json::encode(payload).unwrap().as_bytes()));
            }
            None => {
                try!(curl.get(true));
            }
        }
        if let Some(auth) = auth {
            try!(headers.append(format!("Authorization: {}", auth).as_str()));
        }
        try!(curl.http_headers(headers));
        Ok(curl)
    }
}

struct JsonRequest {
    /// Target host's IP address
    backend: String,
    /// Request path not HTTP Method; HTTP method is setup automatically
    method: String,

    /// Request data; if data is None -> do GET, POST otherwise;
    data: Option<Json>,
}

struct JsonResponse {
}
<commit_msg>more progress<commit_after>use std::io::{self, Write};
use std::sync::{Arc, Mutex};

use curl;
use curl::easy::{Easy, List};
use tokio_curl::Session;
use tokio_core::reactor::Handle;
use rustc_serialize::json::{self, Json};    // XXX: use serde
use futures::{Future, BoxFuture};
use futures::{finished, failed};
use netbuf::Buf;

// HttpClient (service)
//
//  new(curl_session)
//
//  call(req: HttpRequest) -> Future<Response>

struct HttpJsonClient {
    session: Session,
}

impl HttpJsonClient {

    pub fn new(handle: Handle) -> HttpJsonClient {
        HttpJsonClient {
            session: Session::new(handle),
        }
    }

    pub fn perform(&self, req: JsonRequest, auth: Option<String>)
        -> BoxFuture<JsonResponse, io::Error>
    {
        let body_buf = Arc::new(Mutex::new(Buf::new()));

        let curl = match self.build(req, auth, body_buf.clone()) {
            Ok(curl) => curl,
            Err(e) => {
                return failed(io::Error::new(
                    io::ErrorKind::Other, "Curl error"))
                    .boxed()
            }
        };

        self.session.perform(curl)
            .map_err(|e| e.into_error())
            .and_then(move |resp| {
                // TODO: collect & parse response body
                let buf = body_buf.lock().unwrap();
                finished(JsonResponse::from(resp, &buf))
            }).boxed()
    }

    fn build(&self, req: JsonRequest, auth: Option<String>,
        body_buf: Arc<Mutex<Buf>>)
        -> Result<Easy, curl::Error>
    {
        let mut curl = Easy::new();
        let mut headers = List::new();
        try!(curl.forbid_reuse(true));
        try!(curl.url(
            format!("http://{}{}", req.backend, req.method).as_str()));
        match req.data {
            Some(ref payload) => {
                try!(curl.post(true));
                try!(headers.append("Content-Type: application/json"));
                try!(curl.post_fields_copy(
                    json::encode(payload).unwrap().as_bytes()));
            }
            None => {
                try!(curl.get(true));
            }
        }
        if let Some(auth) = auth {
            try!(headers.append(format!("Authorization: {}", auth).as_str()));
        }
        try!(curl.http_headers(headers));

        try!(curl.write_function(move |buf| {
            body_buf.lock().unwrap()
                .write(buf)
                .map_err(|e| {
                    panic!("write respone body error: {:?}", e);
                })
        }));
        Ok(curl)
    }
}

struct JsonRequest {
    /// Target host's IP address
    backend: String,
    /// Request path not HTTP Method; HTTP method is setup automatically
    method: String,

    /// Request data; if data is None -> do GET, POST otherwise;
    data: Option<Json>,
}

struct JsonResponse {
}

impl JsonResponse {
    pub fn from(resp: Easy, body: &Buf) -> JsonResponse {
        JsonResponse {}
    }
}
<|endoftext|>