<commit_before>// Parse ANSI attr code
use std::borrow::Cow;
use std::default::Default;
use std::mem;

use tuikit::prelude::*;
use vte::Perform;

/// An ANSI Parser, will parse one line at a time.
///
/// It will cache the latest attribute used, that means if an attribute affect multiple
/// lines, the parser will recognize it.
pub struct ANSIParser {
    partial_str: String,
    last_attr: Attr,

    stripped: String,
    fragments: Vec<(Attr, Cow<'static, str>)>,
}

impl Default for ANSIParser {
    fn default() -> Self {
        ANSIParser {
            partial_str: String::new(),
            last_attr: Attr::default(),

            stripped: String::new(),
            fragments: Vec::new(),
        }
    }
}

impl Perform for ANSIParser {
    fn print(&mut self, ch: char) {
        self.partial_str.push(ch);
    }

    fn execute(&mut self, byte: u8) {
        match byte {
            // put back \0 \r \n \t
            0x00 | 0x0d | 0x0A | 0x09 => self.partial_str.push(byte as char),
            // ignore all others
            _ => trace!("AnsiParser:execute ignored {:?}", byte),
        }
    }

    fn hook(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool) {
        trace!("AnsiParser:hook ignored {:?}", params);
    }

    fn put(&mut self, byte: u8) {
        trace!("AnsiParser:put ignored {:?}", byte);
    }

    fn unhook(&mut self) {
        trace!("AnsiParser:unhook ignored");
    }

    fn osc_dispatch(&mut self, params: &[&[u8]]) {
        trace!("AnsiParser:osc ignored {:?}", params);
    }

    fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, mode: char) {
        // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
        // Only care about graphic modes, ignore all others

        if mode != 'm' {
            trace!("ignore: params: {:?}, mode: {:?}", params, mode);
            return;
        }

        // \[[m => means reset
        let mut attr = if params.is_empty() {
            Attr::default()
        } else {
            self.last_attr
        };

        let mut iter = params.into_iter();
        while let Some(&code) = iter.next() {
            match code {
                0 => attr = Attr::default(),
                1 => attr.effect |= Effect::BOLD,
                2 => attr.effect |= !Effect::BOLD,
                4 => attr.effect |= Effect::UNDERLINE,
                5 => attr.effect |= Effect::BLINK,
                7 => attr.effect |= Effect::REVERSE,
                num if num >= 30 && num <= 37 => {
                    attr.fg = Color::AnsiValue((num - 30) as u8);
                }
                38 => match iter.next() {
                    Some(2) => {
                        // ESC[ 38;2;<r>;<g>;<b> m Select RGB foreground color
                        let or = iter.next();
                        let og = iter.next();
                        let ob = iter.next();
                        if ob.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }

                        let r = *or.unwrap() as u8;
                        let g = *og.unwrap() as u8;
                        let b = *ob.unwrap() as u8;

                        attr.fg = Color::Rgb(r, g, b);
                    }
                    Some(5) => {
                        // ESC[ 38;5;<n> m Select foreground color
                        let color = iter.next();
                        if color.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }
                        attr.fg = Color::AnsiValue(*color.unwrap() as u8);
                    }
                    _ => {
                        trace!("error on parsing CSI {:?} m", params);
                    }
                },
                39 => attr.fg = Color::Default,
                num if num >= 40 && num <= 47 => {
                    attr.bg = Color::AnsiValue((num - 40) as u8);
                }
                48 => match iter.next() {
                    Some(2) => {
                        // ESC[ 48;2;<r>;<g>;<b> m Select RGB background color
                        let or = iter.next();
                        let og = iter.next();
                        let ob = iter.next();
                        if ob.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }

                        let r = *or.unwrap() as u8;
                        let g = *og.unwrap() as u8;
                        let b = *ob.unwrap() as u8;

                        attr.bg = Color::Rgb(r, g, b);
                    }
                    Some(5) => {
                        // ESC[ 48;5;<n> m Select background color
                        let color = iter.next();
                        if color.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }
                        attr.bg = Color::AnsiValue(*color.unwrap() as u8);
                    }
                    _ => {
                        trace!("ignore CSI {:?} m", params);
                    }
                },
                49 => attr.bg = Color::Default,
                _ => {
                    trace!("ignore CSI {:?} m", params);
                }
            }
        }

        self.attr_change(attr);
    }

    fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {
        // ESC characters are replaced with \[
        self.partial_str.push('"');
        self.partial_str.push('[');
    }
}

impl ANSIParser {
    /// save the partial_str into fragments with current attr
    fn save_str(&mut self) {
        if self.partial_str.is_empty() {
            return;
        }

        let string = mem::replace(&mut self.partial_str, String::new());
        self.stripped.push_str(&string);
        self.fragments.push((self.last_attr, Cow::Owned(string)));
    }

    // accept a new attr
    fn attr_change(&mut self, new_attr: Attr) {
        if new_attr == self.last_attr {
            return;
        }

        self.save_str();
        self.last_attr = new_attr;
    }

    pub fn parse_ansi(&mut self, text: &str) -> AnsiString {
        let mut statemachine = vte::Parser::new();

        for byte in text.as_bytes() {
            statemachine.advance(self, *byte);
        }
        self.save_str();

        let stripped = mem::replace(&mut self.stripped, String::new());
        let fragments = mem::replace(&mut self.fragments, Vec::new());
        AnsiString::new(stripped, fragments)
    }
}

#[derive(Clone, Debug)]
/// A String that contains ANSI state (e.g. colors)
///
/// It is internally represented as Vec<(attr, string)>
pub struct AnsiString {
    stripped: Cow<'static, str>,
    fragments: Vec<(Attr, Cow<'static, str>)>,
}

impl AnsiString {
    pub fn new_empty() -> Self {
        Self {
            stripped: Cow::Owned(String::new()),
            fragments: Vec::new(),
        }
    }

    pub fn new_string(string: String) -> Self {
        let stripped: Cow<'static, str> = Cow::Owned(string);
        Self {
            stripped: stripped.clone(),
            fragments: vec![(Attr::default(), stripped.clone())],
        }
    }

    pub fn new(stripped: String, fragments: Vec<(Attr, Cow<'static, str>)>) -> Self {
        Self {
            stripped: Cow::Owned(stripped),
            fragments,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.fragments.is_empty()
    }

    pub fn into_inner(self) -> String {
        self.stripped.into()
    }

    pub fn iter(&self) -> AnsiStringIterator {
        AnsiStringIterator::new(&self.fragments)
    }

    pub fn has_attrs(&self) -> bool {
        // more than 1 fragments or is not default attr
        self.fragments.len() > 1 || (!self.fragments.is_empty() && self.fragments[0].0 != Attr::default())
    }

    pub fn from_str(raw: &str) -> AnsiString {
        ANSIParser::default().parse_ansi(raw)
    }

    pub fn get_stripped(&self) -> &str {
        &self.stripped
    }
}

/// An iterator over all the (char, attr) characters.
pub struct AnsiStringIterator<'a> {
    fragments: &'a [(Attr, Cow<'a, str>)],
    fragment_idx: usize,
    attr: Attr,
    chars_iter: Option<std::str::Chars<'a>>,
}

impl<'a> AnsiStringIterator<'a> {
    pub fn new(fragments: &'a [(Attr, Cow<'a, str>)]) -> Self {
        Self {
            fragments,
            fragment_idx: 0,
            attr: Attr::default(),
            chars_iter: None,
        }
    }
}

impl<'a> Iterator for AnsiStringIterator<'a> {
    type Item = (char, Attr);

    fn next(&mut self) -> Option<Self::Item> {
        let ch = self.chars_iter.as_mut().and_then(|iter| iter.next());
        match ch {
            Some(c) => Some((c, self.attr)),
            None => {
                if self.fragment_idx >= self.fragments.len() {
                    None
                } else {
                    // try next fragment
                    let (attr, string) = &self.fragments[self.fragment_idx];
                    self.attr = *attr;
                    self.chars_iter.replace(string.chars());
                    self.fragment_idx += 1;
                    self.next()
                }
            }
        }
    }
}

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

    #[test]
    fn test_ansi_iterator() {
        let input = "\x1B[48;2;5;10;15m\x1B[38;2;70;130;180mhi\x1B[0m";
        let ansistring = ANSIParser::default().parse_ansi(input);
        let mut it = ansistring.iter();
        let attr = Attr {
            fg: Color::Rgb(70, 130, 180),
            bg: Color::Rgb(5, 10, 15),
            ..Attr::default()
        };

        assert_eq!(Some(('h', attr)), it.next());
        assert_eq!(Some(('i', attr)), it.next());
        assert_eq!(None, it.next());
    }

    #[test]
    fn test_normal_string() {
        let input = "ab";
        let ansistring = ANSIParser::default().parse_ansi(input);

        assert_eq!(false, ansistring.has_attrs());

        let mut it = ansistring.iter();
        assert_eq!(Some(('a', Attr::default())), it.next());
        assert_eq!(Some(('b', Attr::default())), it.next());
        assert_eq!(None, it.next());

        assert_eq!("ab", ansistring.into_inner())
    }

    #[test]
    fn test_multiple_attributes() {
        let input = "\x1B[1;31mhi";
        let ansistring = ANSIParser::default().parse_ansi(input);
        let mut it = ansistring.iter();
        let attr = Attr {
            fg: Color::AnsiValue(1),
            effect: Effect::BOLD,
            ..Attr::default()
        };

        assert_eq!(Some(('h', attr)), it.next());
        assert_eq!(Some(('i', attr)), it.next());
        assert_eq!(None, it.next());
    }

    #[test]
    fn test_reset() {
        let input = "\x1B[35mA\x1B[mB";
        let ansistring = ANSIParser::default().parse_ansi(input);
        assert_eq!(ansistring.fragments.len(), 2);
    }
}
<commit_msg>fix #246 support \b in ANSI mode<commit_after>// Parse ANSI attr code
use std::borrow::Cow;
use std::default::Default;
use std::mem;

use tuikit::prelude::*;
use vte::Perform;

/// An ANSI Parser, will parse one line at a time.
///
/// It will cache the latest attribute used, that means if an attribute affect multiple
/// lines, the parser will recognize it.
pub struct ANSIParser {
    partial_str: String,
    last_attr: Attr,

    stripped: String,
    fragments: Vec<(Attr, Cow<'static, str>)>,
}

impl Default for ANSIParser {
    fn default() -> Self {
        ANSIParser {
            partial_str: String::new(),
            last_attr: Attr::default(),

            stripped: String::new(),
            fragments: Vec::new(),
        }
    }
}

impl Perform for ANSIParser {
    fn print(&mut self, ch: char) {
        self.partial_str.push(ch);
    }

    fn execute(&mut self, byte: u8) {
        match byte {
            // put back \0 \r \n \b \t
            0x00 | 0x0d | 0x0A | 0x08 | 0x09 => self.partial_str.push(byte as char),
            // ignore all others
            _ => trace!("AnsiParser:execute ignored {:?}", byte),
        }
    }

    fn hook(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool) {
        trace!("AnsiParser:hook ignored {:?}", params);
    }

    fn put(&mut self, byte: u8) {
        trace!("AnsiParser:put ignored {:?}", byte);
    }

    fn unhook(&mut self) {
        trace!("AnsiParser:unhook ignored");
    }

    fn osc_dispatch(&mut self, params: &[&[u8]]) {
        trace!("AnsiParser:osc ignored {:?}", params);
    }

    fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, mode: char) {
        // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
        // Only care about graphic modes, ignore all others

        if mode != 'm' {
            trace!("ignore: params: {:?}, mode: {:?}", params, mode);
            return;
        }

        // \[[m => means reset
        let mut attr = if params.is_empty() {
            Attr::default()
        } else {
            self.last_attr
        };

        let mut iter = params.into_iter();
        while let Some(&code) = iter.next() {
            match code {
                0 => attr = Attr::default(),
                1 => attr.effect |= Effect::BOLD,
                2 => attr.effect |= !Effect::BOLD,
                4 => attr.effect |= Effect::UNDERLINE,
                5 => attr.effect |= Effect::BLINK,
                7 => attr.effect |= Effect::REVERSE,
                num if num >= 30 && num <= 37 => {
                    attr.fg = Color::AnsiValue((num - 30) as u8);
                }
                38 => match iter.next() {
                    Some(2) => {
                        // ESC[ 38;2;<r>;<g>;<b> m Select RGB foreground color
                        let or = iter.next();
                        let og = iter.next();
                        let ob = iter.next();
                        if ob.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }

                        let r = *or.unwrap() as u8;
                        let g = *og.unwrap() as u8;
                        let b = *ob.unwrap() as u8;

                        attr.fg = Color::Rgb(r, g, b);
                    }
                    Some(5) => {
                        // ESC[ 38;5;<n> m Select foreground color
                        let color = iter.next();
                        if color.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }
                        attr.fg = Color::AnsiValue(*color.unwrap() as u8);
                    }
                    _ => {
                        trace!("error on parsing CSI {:?} m", params);
                    }
                },
                39 => attr.fg = Color::Default,
                num if num >= 40 && num <= 47 => {
                    attr.bg = Color::AnsiValue((num - 40) as u8);
                }
                48 => match iter.next() {
                    Some(2) => {
                        // ESC[ 48;2;<r>;<g>;<b> m Select RGB background color
                        let or = iter.next();
                        let og = iter.next();
                        let ob = iter.next();
                        if ob.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }

                        let r = *or.unwrap() as u8;
                        let g = *og.unwrap() as u8;
                        let b = *ob.unwrap() as u8;

                        attr.bg = Color::Rgb(r, g, b);
                    }
                    Some(5) => {
                        // ESC[ 48;5;<n> m Select background color
                        let color = iter.next();
                        if color.is_none() {
                            trace!("ignore CSI {:?} m", params);
                            continue;
                        }
                        attr.bg = Color::AnsiValue(*color.unwrap() as u8);
                    }
                    _ => {
                        trace!("ignore CSI {:?} m", params);
                    }
                },
                49 => attr.bg = Color::Default,
                _ => {
                    trace!("ignore CSI {:?} m", params);
                }
            }
        }

        self.attr_change(attr);
    }

    fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {
        // ESC characters are replaced with \[
        self.partial_str.push('"');
        self.partial_str.push('[');
    }
}

impl ANSIParser {
    /// save the partial_str into fragments with current attr
    fn save_str(&mut self) {
        if self.partial_str.is_empty() {
            return;
        }

        let string = mem::replace(&mut self.partial_str, String::new());
        self.stripped.push_str(&string);
        self.fragments.push((self.last_attr, Cow::Owned(string)));
    }

    // accept a new attr
    fn attr_change(&mut self, new_attr: Attr) {
        if new_attr == self.last_attr {
            return;
        }

        self.save_str();
        self.last_attr = new_attr;
    }

    pub fn parse_ansi(&mut self, text: &str) -> AnsiString {
        let mut statemachine = vte::Parser::new();

        for byte in text.as_bytes() {
            statemachine.advance(self, *byte);
        }
        self.save_str();

        let stripped = mem::replace(&mut self.stripped, String::new());
        let fragments = mem::replace(&mut self.fragments, Vec::new());
        AnsiString::new(stripped, fragments)
    }
}

#[derive(Clone, Debug)]
/// A String that contains ANSI state (e.g. colors)
///
/// It is internally represented as Vec<(attr, string)>
pub struct AnsiString {
    stripped: Cow<'static, str>,
    fragments: Vec<(Attr, Cow<'static, str>)>,
}

impl AnsiString {
    pub fn new_empty() -> Self {
        Self {
            stripped: Cow::Owned(String::new()),
            fragments: Vec::new(),
        }
    }

    pub fn new_string(string: String) -> Self {
        let stripped: Cow<'static, str> = Cow::Owned(string);
        Self {
            stripped: stripped.clone(),
            fragments: vec![(Attr::default(), stripped.clone())],
        }
    }

    pub fn new(stripped: String, fragments: Vec<(Attr, Cow<'static, str>)>) -> Self {
        Self {
            stripped: Cow::Owned(stripped),
            fragments,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.fragments.is_empty()
    }

    pub fn into_inner(self) -> String {
        self.stripped.into()
    }

    pub fn iter(&self) -> AnsiStringIterator {
        AnsiStringIterator::new(&self.fragments)
    }

    pub fn has_attrs(&self) -> bool {
        // more than 1 fragments or is not default attr
        self.fragments.len() > 1 || (!self.fragments.is_empty() && self.fragments[0].0 != Attr::default())
    }

    pub fn from_str(raw: &str) -> AnsiString {
        ANSIParser::default().parse_ansi(raw)
    }

    pub fn get_stripped(&self) -> &str {
        &self.stripped
    }
}

/// An iterator over all the (char, attr) characters.
pub struct AnsiStringIterator<'a> {
    fragments: &'a [(Attr, Cow<'a, str>)],
    fragment_idx: usize,
    attr: Attr,
    chars_iter: Option<std::str::Chars<'a>>,
}

impl<'a> AnsiStringIterator<'a> {
    pub fn new(fragments: &'a [(Attr, Cow<'a, str>)]) -> Self {
        Self {
            fragments,
            fragment_idx: 0,
            attr: Attr::default(),
            chars_iter: None,
        }
    }
}

impl<'a> Iterator for AnsiStringIterator<'a> {
    type Item = (char, Attr);

    fn next(&mut self) -> Option<Self::Item> {
        let ch = self.chars_iter.as_mut().and_then(|iter| iter.next());
        match ch {
            Some(c) => Some((c, self.attr)),
            None => {
                if self.fragment_idx >= self.fragments.len() {
                    None
                } else {
                    // try next fragment
                    let (attr, string) = &self.fragments[self.fragment_idx];
                    self.attr = *attr;
                    self.chars_iter.replace(string.chars());
                    self.fragment_idx += 1;
                    self.next()
                }
            }
        }
    }
}

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

    #[test]
    fn test_ansi_iterator() {
        let input = "\x1B[48;2;5;10;15m\x1B[38;2;70;130;180mhi\x1B[0m";
        let ansistring = ANSIParser::default().parse_ansi(input);
        let mut it = ansistring.iter();
        let attr = Attr {
            fg: Color::Rgb(70, 130, 180),
            bg: Color::Rgb(5, 10, 15),
            ..Attr::default()
        };

        assert_eq!(Some(('h', attr)), it.next());
        assert_eq!(Some(('i', attr)), it.next());
        assert_eq!(None, it.next());
    }

    #[test]
    fn test_normal_string() {
        let input = "ab";
        let ansistring = ANSIParser::default().parse_ansi(input);

        assert_eq!(false, ansistring.has_attrs());

        let mut it = ansistring.iter();
        assert_eq!(Some(('a', Attr::default())), it.next());
        assert_eq!(Some(('b', Attr::default())), it.next());
        assert_eq!(None, it.next());

        assert_eq!("ab", ansistring.into_inner())
    }

    #[test]
    fn test_multiple_attributes() {
        let input = "\x1B[1;31mhi";
        let ansistring = ANSIParser::default().parse_ansi(input);
        let mut it = ansistring.iter();
        let attr = Attr {
            fg: Color::AnsiValue(1),
            effect: Effect::BOLD,
            ..Attr::default()
        };

        assert_eq!(Some(('h', attr)), it.next());
        assert_eq!(Some(('i', attr)), it.next());
        assert_eq!(None, it.next());
    }

    #[test]
    fn test_reset() {
        let input = "\x1B[35mA\x1B[mB";
        let ansistring = ANSIParser::default().parse_ansi(input);
        assert_eq!(ansistring.fragments.len(), 2);
    }
}
<|endoftext|>


<commit_before>//! incremental BLOB I/O
use std::io;
use std::mem;
use std::ptr;

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

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

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

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

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

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

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

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                      Error {
                                          code: ffi::SQLITE_TOOBIG,
                                          message: "buffer too long".to_string(),
                                      }));
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                      Error {
                                          code: ffi::SQLITE_TOOBIG,
                                          message: "buffer too long".to_string(),
                                      }));
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(io::Error::new(io::ErrorKind::Other,
                                      Error {
                                          code: ffi::SQLITE_MISUSE,
                                          message: format!("pos = {} + n = {} > size = {}",
                                                           self.pos,
                                                           n,
                                                           size),
                                      }));
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

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

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

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

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

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

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

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

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert!(blob.write(b"5678901").is_err()); // cannot write past 10
        assert_eq!(4, blob.write(b"5678").unwrap());

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

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

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

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

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

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

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

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

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

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

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

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }
}
<commit_msg>Truncate instead of erroring if asked to read/write too much data from a Blob.<commit_after>//! incremental BLOB I/O
use std::io;
use std::cmp::min;
use std::mem;
use std::ptr;

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

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

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

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

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

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;
use core::str::from_bytes;
use core::vec::const_slice;
use core::cast::transmute;
use core::vec::bytes::copy_memory;
use core::vec::mut_slice;

// Available Result values
enum Result {
  Document(~BsonElement),
  ParseError(bool)
}

// BsonTypes
enum BsonTypes {
  BsonInt32 = 0x10
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64),
  String(@str),
  Object(@mut LinearMap<~str, ~BsonElement>),
}

struct BsonParser;
struct ParserState {
  index: u32,
  document: @BsonElement
}

impl BsonParser {
  fn serialize(&self, object: &BsonElement) -> ~[u8] {
    // Calculate size of final object
    let size = BsonParser::calculateSize(object);
    // Allocate a vector
    let mut data:~[u8] = vec::from_elem(size, 0);
    // Write the data to the vector
    data[3] = ((size >> 24) & 0xff) as u8;
    data[2] = ((size >> 16) & 0xff) as u8;
    data[1] = ((size >> 8) & 0xff) as u8;
    data[0] = (size & 0xff) as u8;
    // Starting index
    let mut index = 4;
    // io::println(fmt!("==== vector :: %?", data));

    // Current index
    // Unpack the object
    match object {
      &Object(map) => {
        // io::println("deserialize Object");

        // Get each key
        for map.each_key |k| {
          // Let's figure out what type of object we have
          match map.find(k) {
            Some(&~Int32(number)) => {
              // Set the data type
              data[index] = BsonInt32 as u8;
              // Adjust index
              index += 1;

              // Copy the field value name to the vector
              copy_memory(mut_slice(data, index, size), k.to_bytes(), k.len());

              // Adjust the index position
              index += k.len() + 1;

              // io::println("========= INT32");
              data[index + 3] = ((number >> 24) & 0xff) as u8;
              data[index + 2] = ((number >> 16) & 0xff) as u8;
              data[index + 1] = ((number >> 8) & 0xff) as u8;
              data[index] = (number & 0xff) as u8;
              index += 4;
            }
            _ => ()
          }
        }

        // io::println(fmt!("==== vector :: %?", data));
      }
      _ => ()
    }

    data
  }

  fn serialize_object(object: &BsonElement) {

  }

  fn calculateSize(object: &BsonElement) -> uint {
    let mut size:uint = 0;

    // Unpack the object
    match object {
      &Object(map) => {
        // Add the header and tail of the document
        size += 5;
        // Iterate over all the fields
        for map.each_key |k| {
          // String length + 0 terminating byte + type
          size += k.len() as uint + 1 + 1;
          // Match the key
          size += match map.find(k) {
            Some(&~Int32(_)) => 4,
            Some(&~Int64(_)) => 8,
            _ => 0
          };
        };
      },
      _ => ()
    }

    size
  }

  fn deserialize(&self, data: &[u8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(~Object(@mut LinearMap::new()));
    }

    // Parse the document
    let object = BsonParser::deserialize_loop(data, @mut 0i64);
    // return the document
    @Document(object)
  }

  fn deserialize_loop(data: &[u8], index: &mut i64) -> ~BsonElement {
    // Create an empty object
    let object: ~BsonElement = ~Object(@mut LinearMap::new());
    // Decode the document size
    let size = data[*index] as u32;
    // Adjust the location of the index
    *index = *index + 4;
    // Loop until we are done
    loop {
      // Get bson type
      let bson_type = data[*index];
      // Adjust to name of the field
      *index += 1;
      // If type is 0x00 we are done
      if bson_type == 0x00 {
        break;
      }

      // Decode the name from the cstring
      let name = BsonParser::extract_string(*index, data);
      // Adjust the index to point to the data
      *index += name.len() as i64 + 1;

      // Access the internal map
      match object {
        ~Object(map) => {
          match bson_type as u8 {
            0x02 => {
                map.insert(name, BsonParser::parseString(index, data));
              },
            0x10 => {
                map.insert(name, BsonParser::parseInt32(index, data));
              },
            0x12 => {
                map.insert(name, BsonParser::parseInt64(index, data));
              },
            0x03 => {
                // Create a new object
                let new_object = BsonParser::deserialize_loop(data, index);
                // Add to the map
                map.insert(name, new_object);
              }
            _ => ()
          }
        }
        _ => ()
      };
    }

    object
  }

  fn extract_string(index:i64, data: &[u8]) -> ~str {
    unsafe {
      let data2: &[i8] = transmute(data);
      // Unpack the name of the field
      from_c_str(&data2[index])
    }
  }

  fn parseString(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // unpack the string size
    let size:u32 = data[*index] as u32;
    // Adjust the index
    *index = *index + 4;
    // unpack the data as a string
    let string = from_bytes(const_slice(data, *index as uint, (*index + (size - 1) as i64) as uint)).to_managed();
    // return string
    ~String(string)
  }

  fn parseInt32(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int32(data[*index] as i32);
    // Adjust index
    *index += 4;
    // Return the value
    value
  }

  fn parseInt64(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int64(data[*index] as i64);
    // Adjust index
    *index += 8;
    // Return the value
    value
  }
}

/**
 * Tests
 */
#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 1);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int32_serialize_test() {
  let parser:BsonParser = BsonParser;
  // Build a BSON object
  let map = @mut LinearMap::new();
  map.insert(~"a", ~Int32(1));
  let object:~BsonElement = ~Object(map);
  // Serialize the object
  let data = parser.serialize(object);
  // io::println(fmt!("================ data :: %?", data));
  let expectedData = ~[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00];
  assert_eq!(data, expectedData);
  // io::println(fmt!("================ data :: %?", expectedData));
  // io::println(fmt!("================ data size :: %?", expectedData.len()));
  // let o = parser.deserialize(data);

  // let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  // fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
  //   match map.find(&~"a") {
  //     Some(&~Int32(number)) => {
  //       assert_eq!(number, 1);
  //     },
  //     _ => fail!()
  //   }
  // }

  // match result {
  //   @Document(~Object(map)) => process_map(map),
  //   @Document(_) => (),
  //   @ParseError(_) => ()
  // }
}

#[test]
fn simple_string_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x18, 0x00, 0x00, 0x00, 0x02, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~String(final)) => {
        assert_eq!(final, @"hello world");
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int64_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x10, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn sub_document_test() {
  // {a:{b:1}, c:2}
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x1b, 0x00, 0x00, 0x00, 0x03, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);

  // Validate the result
  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Object(object_map)) => {

        // Locate the internal object
        match object_map.find(&~"b") {
          Some(&~Int32(number)) => {
            assert_eq!(number, 1);
          },
          _ => fail!()
        }
      }
      _ => fail!()
    }

    match map.find(&~"c") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}<commit_msg>Managed to pass around mutable vector<commit_after>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;
use core::str::from_bytes;
use core::vec::const_slice;
use core::cast::transmute;
use core::vec::bytes::copy_memory;
use core::vec::slice;

// Available Result values
enum Result {
  Document(~BsonElement),
  ParseError(bool)
}

// BsonTypes
enum BsonTypes {
  BsonInt32 = 0x10
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64),
  String(@str),
  Object(@mut LinearMap<~str, ~BsonElement>),
}

struct BsonParser;
struct ParserState {
  index: u32,
  document: @BsonElement
}

impl BsonParser {
  fn serialize_object(&self, object: &BsonElement, data: &mut [u8], index: &mut uint) {
    io::println(fmt!("+++++++++++ serialize_object :: %?", data));
    // data.as_mut_buf()
    // data[0] = 0x10;
    // Unpack the object
    match object {
      &Object(map) => {
        // io::println("deserialize Object");

        // Get each key
        for map.each_key |k| {
          // Let's figure out what type of object we have
          match map.find(k) {
            Some(&~Int32(number)) => {
              // Set the data type
              data[*index] = BsonInt32 as u8;
              // Adjust index
              *index += 1;

              // Copy the field value name to the vector
              copy_memory(vec::mut_slice(data, *index, *index + k.len()), k.to_bytes(), k.len());

              // Adjust the index position
              *index += k.len() + 1;

              // io::println("========= INT32");
              data[*index + 3] = ((number >> 24) & 0xff) as u8;
              data[*index + 2] = ((number >> 16) & 0xff) as u8;
              data[*index + 1] = ((number >> 8) & 0xff) as u8;
              data[*index] = (number & 0xff) as u8;
              *index += 4;
            }
            _ => ()
          }
        }
      }
      _ => ()
    }
  }

  fn serialize(&self, object: &BsonElement) -> ~[u8] {
    // Calculate size of final object
    let size = BsonParser::calculateSize(object);
    // Allocate a vector
    let mut data = vec::from_elem(size, 0);
    // let mut data = @[0, ..20];
    // // Write the data to the vector
    data[3] = ((size >> 24) & 0xff) as u8;
    data[2] = ((size >> 16) & 0xff) as u8;
    data[1] = ((size >> 8) & 0xff) as u8;
    data[0] = (size & 0xff) as u8;
    // Starting index
    let mut index = @mut 4;
    io::println(fmt!("==== vector :: %?", data));

    // Current index
    self.serialize_object(object, data, index);
    io::println(fmt!("==== vector :: %?", data));

    // data
    data
  }

  fn calculateSize(object: &BsonElement) -> uint {
    let mut size:uint = 0;

    // Unpack the object
    match object {
      &Object(map) => {
        // Add the header and tail of the document
        size += 5;
        // Iterate over all the fields
        for map.each_key |k| {
          // String length + 0 terminating byte + type
          size += k.len() as uint + 1 + 1;
          // Match the key
          size += match map.find(k) {
            Some(&~Int32(_)) => 4,
            Some(&~Int64(_)) => 8,
            _ => 0
          };
        };
      },
      _ => ()
    }

    size
  }

  fn deserialize(&self, data: &[u8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(~Object(@mut LinearMap::new()));
    }

    // Parse the document
    let object = BsonParser::deserialize_loop(data, @mut 0i64);
    // return the document
    @Document(object)
  }

  fn deserialize_loop(data: &[u8], index: &mut i64) -> ~BsonElement {
    // Create an empty object
    let object: ~BsonElement = ~Object(@mut LinearMap::new());
    // Decode the document size
    let size = data[*index] as u32;
    // Adjust the location of the index
    *index = *index + 4;
    // Loop until we are done
    loop {
      // Get bson type
      let bson_type = data[*index];
      // Adjust to name of the field
      *index += 1;
      // If type is 0x00 we are done
      if bson_type == 0x00 {
        break;
      }

      // Decode the name from the cstring
      let name = BsonParser::extract_string(*index, data);
      // Adjust the index to point to the data
      *index += name.len() as i64 + 1;

      // Access the internal map
      match object {
        ~Object(map) => {
          match bson_type as u8 {
            0x02 => {
                map.insert(name, BsonParser::parseString(index, data));
              },
            0x10 => {
                map.insert(name, BsonParser::parseInt32(index, data));
              },
            0x12 => {
                map.insert(name, BsonParser::parseInt64(index, data));
              },
            0x03 => {
                // Create a new object
                let new_object = BsonParser::deserialize_loop(data, index);
                // Add to the map
                map.insert(name, new_object);
              }
            _ => ()
          }
        }
        _ => ()
      };
    }

    object
  }

  fn extract_string(index:i64, data: &[u8]) -> ~str {
    unsafe {
      let data2: &[i8] = transmute(data);
      // Unpack the name of the field
      from_c_str(&data2[index])
    }
  }

  fn parseString(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // unpack the string size
    let size:u32 = data[*index] as u32;
    // Adjust the index
    *index = *index + 4;
    // unpack the data as a string
    let string = from_bytes(const_slice(data, *index as uint, (*index + (size - 1) as i64) as uint)).to_managed();
    // return string
    ~String(string)
  }

  fn parseInt32(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int32(data[*index] as i32);
    // Adjust index
    *index += 4;
    // Return the value
    value
  }

  fn parseInt64(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int64(data[*index] as i64);
    // Adjust index
    *index += 8;
    // Return the value
    value
  }
}

/**
 * Tests
 */
#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 1);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int32_serialize_test() {
  let parser:BsonParser = BsonParser;
  // Build a BSON object
  let map = @mut LinearMap::new();
  map.insert(~"a", ~Int32(1));
  let object:~BsonElement = ~Object(map);
  // Serialize the object
  let data = parser.serialize(object);
  let expectedData = ~[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00];
  // Validate equality
  assert_eq!(data, expectedData);
}

#[test]
fn simple_string_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x18, 0x00, 0x00, 0x00, 0x02, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~String(final)) => {
        assert_eq!(final, @"hello world");
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int64_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x10, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn sub_document_test() {
  // {a:{b:1}, c:2}
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x1b, 0x00, 0x00, 0x00, 0x03, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);

  // Validate the result
  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Object(object_map)) => {

        // Locate the internal object
        match object_map.find(&~"b") {
          Some(&~Int32(number)) => {
            assert_eq!(number, 1);
          },
          _ => fail!()
        }
      }
      _ => fail!()
    }

    match map.find(&~"c") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}<|endoftext|>


<commit_before>//! Macro ABI for version 1.63 of rustc

#[allow(dead_code)]
#[doc(hidden)]
mod proc_macro;

#[allow(dead_code)]
#[doc(hidden)]
mod rustc_server;

use libloading::Library;
use proc_macro_api::ProcMacroKind;

use super::PanicMessage;

pub use rustc_server::TokenStream;

pub(crate) struct Abi {
    exported_macros: Vec<proc_macro::bridge::client::ProcMacro>,
}

impl From<proc_macro::bridge::PanicMessage> for PanicMessage {
    fn from(p: proc_macro::bridge::PanicMessage) -> Self {
        Self { message: p.as_str().map(|s| s.to_string()) }
    }
}

impl Abi {
    pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result<Abi, libloading::Error> {
        let macros: libloading::Symbol<&&[proc_macro::bridge::client::ProcMacro]> =
            lib.get(symbol_name.as_bytes())?;
        Ok(Self { exported_macros: macros.to_vec() })
    }

    pub fn expand(
        &self,
        macro_name: &str,
        macro_body: &tt::Subtree,
        attributes: Option<&tt::Subtree>,
    ) -> Result<tt::Subtree, PanicMessage> {
        let parsed_body = TokenStream::with_subtree(macro_body.clone());

        let parsed_attributes =
            attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone()));

        for proc_macro in &self.exported_macros {
            match proc_macro {
                proc_macro::bridge::client::ProcMacro::CustomDerive {
                    trait_name, client, ..
                } if *trait_name == macro_name => {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                proc_macro::bridge::client::ProcMacro::Bang { name, client }
                    if *name == macro_name =>
                {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                proc_macro::bridge::client::ProcMacro::Attr { name, client }
                    if *name == macro_name =>
                {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_attributes,
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                _ => continue,
            }
        }

        Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into())
    }

    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
        self.exported_macros
            .iter()
            .map(|proc_macro| match proc_macro {
                proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
                    (trait_name.to_string(), ProcMacroKind::CustomDerive)
                }
                proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
                    (name.to_string(), ProcMacroKind::FuncLike)
                }
                proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
                    (name.to_string(), ProcMacroKind::Attr)
                }
            })
            .collect()
    }
}
<commit_msg>Remove macro ABI version from doc comment<commit_after>//! Proc macro ABI.

#[allow(dead_code)]
#[doc(hidden)]
mod proc_macro;

#[allow(dead_code)]
#[doc(hidden)]
mod rustc_server;

use libloading::Library;
use proc_macro_api::ProcMacroKind;

use super::PanicMessage;

pub use rustc_server::TokenStream;

pub(crate) struct Abi {
    exported_macros: Vec<proc_macro::bridge::client::ProcMacro>,
}

impl From<proc_macro::bridge::PanicMessage> for PanicMessage {
    fn from(p: proc_macro::bridge::PanicMessage) -> Self {
        Self { message: p.as_str().map(|s| s.to_string()) }
    }
}

impl Abi {
    pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result<Abi, libloading::Error> {
        let macros: libloading::Symbol<&&[proc_macro::bridge::client::ProcMacro]> =
            lib.get(symbol_name.as_bytes())?;
        Ok(Self { exported_macros: macros.to_vec() })
    }

    pub fn expand(
        &self,
        macro_name: &str,
        macro_body: &tt::Subtree,
        attributes: Option<&tt::Subtree>,
    ) -> Result<tt::Subtree, PanicMessage> {
        let parsed_body = TokenStream::with_subtree(macro_body.clone());

        let parsed_attributes =
            attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone()));

        for proc_macro in &self.exported_macros {
            match proc_macro {
                proc_macro::bridge::client::ProcMacro::CustomDerive {
                    trait_name, client, ..
                } if *trait_name == macro_name => {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                proc_macro::bridge::client::ProcMacro::Bang { name, client }
                    if *name == macro_name =>
                {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                proc_macro::bridge::client::ProcMacro::Attr { name, client }
                    if *name == macro_name =>
                {
                    let res = client.run(
                        &proc_macro::bridge::server::SameThread,
                        rustc_server::Rustc::default(),
                        parsed_attributes,
                        parsed_body,
                        true,
                    );
                    return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
                }
                _ => continue,
            }
        }

        Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into())
    }

    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
        self.exported_macros
            .iter()
            .map(|proc_macro| match proc_macro {
                proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
                    (trait_name.to_string(), ProcMacroKind::CustomDerive)
                }
                proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
                    (name.to_string(), ProcMacroKind::FuncLike)
                }
                proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
                    (name.to_string(), ProcMacroKind::Attr)
                }
            })
            .collect()
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::Value;

use update::Update;
use view::View;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, View>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        let meth = method.as_str().unwrap();
                        if meth == "set_style" || meth == "scroll_to" || meth == "update" {
                            let request = json!([method.clone(), params.clone()]);
                            update_tx.send(request).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        let view = View::new(file.to_string());
        core.views.insert(view_id.clone(), view);
        core.current_view = view_id;
        core
    }

    pub fn update(&mut self, update: &Update) {
        let mut view = self.view();
        view.update(update);
        self.views.insert(self.current_view.clone(), view);
    }

    pub fn view(&self) -> View {
        self.views.clone()[&self.current_view].clone()
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = json!({
            "id": self.rpc_index,
            "method": method,
            "params": params,
        });
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = json!({
            "method": method,
            "params": params,
        });
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let msg = json!({
            "method": method,
            "view_id": &self.current_view,
            "params": params.unwrap_or(json!([])),
        });
        info!(">>> {:?}", msg);
        self.notify("edit", msg);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let msg = json!({
            "method": method,
            "view_id": &self.current_view,
            "params": params.unwrap_or(json!([])),
        });
        self.call_sync("edit", msg)
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let msg: Value;
        if let Some(file_path) = file_path {
            msg = json!({"file_path": file_path});
        } else {
            msg = json!({});
        }
        self.call_sync("new_view", msg)
    }

    pub fn save(&mut self) {
        let views = self.views.clone();
        let save_params = json!({
            "view_id": &self.current_view.clone(),
            "file_path": &views[&self.current_view].filepath.clone(),
        });
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(json!({"filename": filename})));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(json!({"chars": ch})));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(json!([start, end])));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(json!([line, column, 0, 1])));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(json!([line, column, 0, 1])));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(json!({"chars": s})));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<commit_msg>clippy: or_fun_call<commit_after>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::Value;

use update::Update;
use view::View;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, View>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        let meth = method.as_str().unwrap();
                        if meth == "set_style" || meth == "scroll_to" || meth == "update" {
                            let request = json!([method.clone(), params.clone()]);
                            update_tx.send(request).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        let view = View::new(file.to_string());
        core.views.insert(view_id.clone(), view);
        core.current_view = view_id;
        core
    }

    pub fn update(&mut self, update: &Update) {
        let mut view = self.view();
        view.update(update);
        self.views.insert(self.current_view.clone(), view);
    }

    pub fn view(&self) -> View {
        self.views.clone()[&self.current_view].clone()
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = json!({
            "id": self.rpc_index,
            "method": method,
            "params": params,
        });
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = json!({
            "method": method,
            "params": params,
        });
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let msg = json!({
            "method": method,
            "view_id": &self.current_view,
            "params": params.unwrap_or_else(|| Value::Array(vec![])),
        });
        info!(">>> {:?}", msg);
        self.notify("edit", msg);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let msg = json!({
            "method": method,
            "view_id": &self.current_view,
            "params": params.unwrap_or_else(|| Value::Array(vec![])),
        });
        self.call_sync("edit", msg)
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let msg: Value;
        if let Some(file_path) = file_path {
            msg = json!({"file_path": file_path});
        } else {
            msg = json!({});
        }
        self.call_sync("new_view", msg)
    }

    pub fn save(&mut self) {
        let views = self.views.clone();
        let save_params = json!({
            "view_id": &self.current_view.clone(),
            "file_path": &views[&self.current_view].filepath.clone(),
        });
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(json!({"filename": filename})));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(json!({"chars": ch})));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(json!([start, end])));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(json!([line, column, 0, 1])));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(json!([line, column, 0, 1])));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(json!({"chars": s})));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<|endoftext|>