<commit_before>use super::*;

pub(super) fn static_(p: &mut Parser, m: Marker) {
    const_or_static(p, m, T![static], STATIC)
}

pub(super) fn konst(p: &mut Parser, m: Marker) {
    const_or_static(p, m, T![const], CONST)
}

fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
    assert!(p.at(kw));
    p.bump(kw);
    p.eat(T![mut]);

    // Allow `_` in place of an identifier in a `const`.
    let is_const_underscore = kw == T![const] && p.eat(T![_]);
    if !is_const_underscore {
        name(p);
    }

    // test_err static_underscore
    // static _: i32 = 5;
    if p.at(T![:]) {
        types::ascription(p);
    } else {
        p.error("missing type for `const` or `static`")
    }
    if p.eat(T![=]) {
        expressions::expr(p);
    }
    p.expect(T![;]);
    m.complete(p, def);
}
<commit_msg>minor: cleanup const parsing<commit_after>use super::*;

pub(super) fn konst(p: &mut Parser, m: Marker) {
    p.bump(T![const]);
    const_or_static(p, m, true)
}

pub(super) fn static_(p: &mut Parser, m: Marker) {
    p.bump(T![static]);
    const_or_static(p, m, false)
}

fn const_or_static(p: &mut Parser, m: Marker, is_const: bool) {
    p.eat(T![mut]);

    // Allow `_` in place of an identifier in a `const`.
    let is_const_underscore = is_const && p.eat(T![_]);
    if !is_const_underscore {
        name(p);
    }

    // test_err static_underscore
    // static _: i32 = 5;
    if p.at(T![:]) {
        types::ascription(p);
    } else {
        p.error("missing type for `const` or `static`")
    }
    if p.eat(T![=]) {
        expressions::expr(p);
    }
    p.expect(T![;]);
    m.complete(p, if is_const { CONST } else { STATIC });
}
<|endoftext|>


<commit_before>use list::Node;
use rawlink::RawLink;

#[derive(Debug)]
pub struct NumberedNode {
    pub number: usize,
    prev: RawLink<NumberedNode>,
    next: RawLink<NumberedNode>,
}

impl NumberedNode {
    pub fn new(number: usize) -> Self {
        NumberedNode {
            number: number,
            prev: RawLink::none(),
            next: RawLink::none(),
        }
    }
}

impl Node for NumberedNode {
    fn prev(&self) -> &RawLink<Self> {
        &self.prev
    }

    fn next(&self) -> &RawLink<Self> {
        &self.next
    }

    fn prev_mut(&mut self) -> &mut RawLink<Self> {
        &mut self.prev
    }

    fn next_mut(&mut self) -> &mut RawLink<Self> {
        &mut self.next
    }
}

impl PartialEq for NumberedNode {
    fn eq(&self, rhs: &Self) -> bool { self.number == rhs.number }
}

mod boxed {
    use std::boxed::Box;

    use list::ListNode;
    use super::*;

    type TestList = ListNode<Box<NumberedNode>, NumberedNode>;

    #[test]
    fn not_empty_after_push() {
        let mut list = TestList::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);

        assert!(list.is_empty());

        list.push_front(box NumberedNode::new(1));

        assert!(!list.is_empty());
    }

    #[test]
    fn contents_after_first_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.front().unwrap().number, 1);
    }

    #[test]
    fn head_tail_same_first_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.front().unwrap().number, 1);
        assert_eq!(list.back().unwrap().number, 1);
        assert_eq!(list.front().unwrap(), list.back().unwrap());
    }

    #[test]
    fn head_tail_not_same_second_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(0));
        list.push_front(box NumberedNode::new(1));

        assert!(list.front().unwrap() != list.back().unwrap());
    }

    #[test]
    fn contents_after_pushes() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(0));
        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.back().unwrap().number, 0);
        assert_eq!(list.front().unwrap().number, 1);

        list.push_back(box NumberedNode::new(2));
        assert_eq!(list.back().unwrap().number, 2);
        assert_eq!(list.front().unwrap().number, 1);

        list.push_back(box NumberedNode::new(3));
        assert_eq!(list.back().unwrap().number, 3);
        assert_eq!(list.front().unwrap().number, 1);

        assert!(!list.is_empty());
    }

}

// mod mut_ptr {
//     use list::ListNode;
//     use super::*;
//
//     type TestList<'a> = ListNode<&'a mut NumberedNode, NumberedNode>;
//
//     #[test]
//     fn not_empty_after_push() {
//         let mut list = TestList::new();
//
//         assert_eq!(list.front(), None);
//         assert_eq!(list.back(), None);
//
//         assert!(list.is_empty());
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert!(!list.is_empty());
//     }
//
//     #[test]
//     fn contents_after_first_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.front().unwrap().number, 1);
//     }
//
//
//     #[test]
//     fn head_tail_same_first_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.front().unwrap().number, 1);
//         assert_eq!(list.back().unwrap().number, 1);
//         assert_eq!(list.front().unwrap(), list.back().unwrap());
//     }
//
//     #[test]
//     fn head_tail_not_same_second_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(0));
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert!(list.front().unwrap() != list.back().unwrap());
//     }
//
//
//     #[test]
//     fn contents_after_pushes() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(0));
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.back().unwrap().number, 0);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         list.push_back(&mut NumberedNode::new(2));
//         assert_eq!(list.back().unwrap().number, 2);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         list.push_back(&mut NumberedNode::new(3));
//         assert_eq!(list.back().unwrap().number, 3);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         assert!(!list.is_empty());
//     }
//
// }
<commit_msg>[intrusive] Add unit tests for List.pop_front() and pop_back()<commit_after>use list::Node;
use rawlink::RawLink;

#[derive(Debug)]
pub struct NumberedNode {
    pub number: usize,
    prev: RawLink<NumberedNode>,
    next: RawLink<NumberedNode>,
}

impl NumberedNode {
    pub fn new(number: usize) -> Self {
        NumberedNode {
            number: number,
            prev: RawLink::none(),
            next: RawLink::none(),
        }
    }
}

impl Node for NumberedNode {
    fn prev(&self) -> &RawLink<Self> {
        &self.prev
    }

    fn next(&self) -> &RawLink<Self> {
        &self.next
    }

    fn prev_mut(&mut self) -> &mut RawLink<Self> {
        &mut self.prev
    }

    fn next_mut(&mut self) -> &mut RawLink<Self> {
        &mut self.next
    }
}

impl PartialEq for NumberedNode {
    fn eq(&self, rhs: &Self) -> bool { self.number == rhs.number }
}

mod boxed {
    use std::boxed::Box;

    use list::ListNode;
    use super::*;

    type TestList = ListNode<Box<NumberedNode>, NumberedNode>;

    #[test]
    fn not_empty_after_push() {
        let mut list = TestList::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);

        assert!(list.is_empty());

        list.push_front(box NumberedNode::new(1));

        assert!(!list.is_empty());
    }

    #[test]
    fn contents_after_first_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.front().unwrap().number, 1);
    }

    #[test]
    fn head_tail_same_first_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.front().unwrap().number, 1);
        assert_eq!(list.back().unwrap().number, 1);
        assert_eq!(list.front().unwrap(), list.back().unwrap());
    }

    #[test]
    fn head_tail_not_same_second_push() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(0));
        list.push_front(box NumberedNode::new(1));

        assert!(list.front().unwrap() != list.back().unwrap());
    }

    #[test]
    fn contents_after_pushes() {
        let mut list = TestList::new();

        list.push_front(box NumberedNode::new(0));
        list.push_front(box NumberedNode::new(1));

        assert_eq!(list.back().unwrap().number, 0);
        assert_eq!(list.front().unwrap().number, 1);

        list.push_back(box NumberedNode::new(2));
        assert_eq!(list.back().unwrap().number, 2);
        assert_eq!(list.front().unwrap().number, 1);

        list.push_back(box NumberedNode::new(3));
        assert_eq!(list.back().unwrap().number, 3);
        assert_eq!(list.front().unwrap().number, 1);

        assert!(!list.is_empty());
    }

    #[test]
    fn test_pop_front() {
        let mut list = TestList::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);
        assert!(list.is_empty());

        list.push_front(Box::new(NumberedNode::new(2)));

        assert!(!list.is_empty());
        assert_eq!(list.front(), list.back());

        list.push_front(Box::new(NumberedNode::new(1)));
        list.push_front(Box::new(NumberedNode::new(0)));

        assert_eq!(list.front().unwrap().number, 0);
        assert_eq!(list.back().unwrap().number, 2);

        list.push_back(Box::new(NumberedNode::new(3)));
        assert_eq!(list.back().unwrap().number, 3);

        list.push_back(Box::new(NumberedNode::new(4)));
        assert_eq!(list.back().unwrap().number, 4);

        assert!(!list.is_empty());

        assert_eq!(list.pop_front().unwrap().number, 0);
        assert_eq!(list.pop_front().unwrap().number, 1);
        assert_eq!(list.pop_front().unwrap().number, 2);
        assert_eq!(list.pop_front().unwrap().number, 3);
        assert_eq!(list.pop_front().unwrap().number, 4);

        assert!(list.is_empty());
        assert_eq!(list.pop_front(), None);
    }

    #[test]
    fn test_pop_back() {
        let mut list = TestList::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);
        assert!(list.is_empty());

        list.push_front(Box::new(NumberedNode::new(2)));

        assert!(!list.is_empty());
        assert_eq!(list.front(), list.back());

        list.push_front(Box::new(NumberedNode::new(1)));
        list.push_front(Box::new(NumberedNode::new(0)));

        assert_eq!(list.front().unwrap().number, 0);
        assert_eq!(list.back().unwrap().number, 2);

        list.push_back(Box::new(NumberedNode::new(3)));
        assert_eq!(list.back().unwrap().number, 3);

        list.push_back(Box::new(NumberedNode::new(4)));
        assert_eq!(list.back().unwrap().number, 4);

        assert!(!list.is_empty());

        assert_eq!(list.pop_back().unwrap().number, 4);
        assert_eq!(list.pop_back().unwrap().number, 3);
        assert_eq!(list.pop_back().unwrap().number, 2);
        assert_eq!(list.pop_back().unwrap().number, 1);
        assert_eq!(list.pop_back().unwrap().number, 0);

        assert!(list.is_empty());
        assert_eq!(list.pop_back(), None);
    }

}

// mod mut_ptr {
//     use list::ListNode;
//     use super::*;
//
//     type TestList<'a> = ListNode<&'a mut NumberedNode, NumberedNode>;
//
//     #[test]
//     fn not_empty_after_push() {
//         let mut list = TestList::new();
//
//         assert_eq!(list.front(), None);
//         assert_eq!(list.back(), None);
//
//         assert!(list.is_empty());
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert!(!list.is_empty());
//     }
//
//     #[test]
//     fn contents_after_first_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.front().unwrap().number, 1);
//     }
//
//
//     #[test]
//     fn head_tail_same_first_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.front().unwrap().number, 1);
//         assert_eq!(list.back().unwrap().number, 1);
//         assert_eq!(list.front().unwrap(), list.back().unwrap());
//     }
//
//     #[test]
//     fn head_tail_not_same_second_push() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(0));
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert!(list.front().unwrap() != list.back().unwrap());
//     }
//
//
//     #[test]
//     fn contents_after_pushes() {
//         let mut list = TestList::new();
//
//         list.push_front(&mut NumberedNode::new(0));
//         list.push_front(&mut NumberedNode::new(1));
//
//         assert_eq!(list.back().unwrap().number, 0);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         list.push_back(&mut NumberedNode::new(2));
//         assert_eq!(list.back().unwrap().number, 2);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         list.push_back(&mut NumberedNode::new(3));
//         assert_eq!(list.back().unwrap().number, 3);
//         assert_eq!(list.front().unwrap().number, 1);
//
//         assert!(!list.is_empty());
//     }
//
// }
<|endoftext|>


<commit_before>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

<commit_msg>entry.rs: Add documentation<commit_after>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

/**
 * An Entry of the store
 *
 * Contains location, header and content part.
 */
#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

<|endoftext|>


<commit_before>// bindgen.rs was created with bindgen 0.15.0 against sqlite3 3.8.10

#![allow(non_snake_case)]

extern crate libc;

pub use self::bindgen::*;

use std::mem;
use libc::c_int;

mod bindgen;

pub const SQLITE_OK        : c_int =   0;
pub const SQLITE_ERROR     : c_int =   1;
pub const SQLITE_INTERNAL  : c_int =   2;
pub const SQLITE_PERM      : c_int =   3;
pub const SQLITE_ABORT     : c_int =   4;
pub const SQLITE_BUSY      : c_int =   5;
pub const SQLITE_LOCKED    : c_int =   6;
pub const SQLITE_NOMEM     : c_int =   7;
pub const SQLITE_READONLY  : c_int =   8;
pub const SQLITE_INTERRUPT : c_int =   9;
pub const SQLITE_IOERR     : c_int =  10;
pub const SQLITE_CORRUPT   : c_int =  11;
pub const SQLITE_NOTFOUND  : c_int =  12;
pub const SQLITE_FULL      : c_int =  13;
pub const SQLITE_CANTOPEN  : c_int =  14;
pub const SQLITE_PROTOCOL  : c_int =  15;
pub const SQLITE_EMPTY     : c_int =  16;
pub const SQLITE_SCHEMA    : c_int =  17;
pub const SQLITE_TOOBIG    : c_int =  18;
pub const SQLITE_CONSTRAINT: c_int =  19;
pub const SQLITE_MISMATCH  : c_int =  20;
pub const SQLITE_MISUSE    : c_int =  21;
pub const SQLITE_NOLFS     : c_int =  22;
pub const SQLITE_AUTH      : c_int =  23;
pub const SQLITE_FORMAT    : c_int =  24;
pub const SQLITE_RANGE     : c_int =  25;
pub const SQLITE_NOTADB    : c_int =  26;
pub const SQLITE_NOTICE    : c_int =  27;
pub const SQLITE_WARNING   : c_int =  28;
pub const SQLITE_ROW       : c_int = 100;
pub const SQLITE_DONE      : c_int = 101;

// SQLite datatype constants.
pub const SQLITE_INTEGER : c_int = 1;
pub const SQLITE_FLOAT   : c_int = 2;
pub const SQLITE_TEXT    : c_int = 3;
pub const SQLITE_BLOB    : c_int = 4;
pub const SQLITE_NULL    : c_int = 5;

pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(0isize) })
}

pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(-1isize) })
}

pub fn code_to_str(code: c_int) -> &'static str {
    match code {
        SQLITE_OK        => "Successful result",
        SQLITE_ERROR     => "SQL error or missing database",
        SQLITE_INTERNAL  => "Internal logic error in SQLite",
        SQLITE_PERM      => "Access permission denied",
        SQLITE_ABORT     => "Callback routine requested an abort",
        SQLITE_BUSY      => "The database file is locked",
        SQLITE_LOCKED    => "A table in the database is locked",
        SQLITE_NOMEM     => "A malloc() failed",
        SQLITE_READONLY  => "Attempt to write a readonly database",
        SQLITE_INTERRUPT => "Operation terminated by sqlite3_interrupt()",
        SQLITE_IOERR     => "Some kind of disk I/O error occurred",
        SQLITE_CORRUPT   => "The database disk image is malformed",
        SQLITE_NOTFOUND  => "Unknown opcode in sqlite3_file_control()",
        SQLITE_FULL      => "Insertion failed because database is full",
        SQLITE_CANTOPEN  => "Unable to open the database file",
        SQLITE_PROTOCOL  => "Database lock protocol error",
        SQLITE_EMPTY     => "Database is empty",
        SQLITE_SCHEMA    => "The database schema changed",
        SQLITE_TOOBIG    => "String or BLOB exceeds size limit",
        SQLITE_CONSTRAINT=> "Abort due to constraint violation",
        SQLITE_MISMATCH  => "Data type mismatch",
        SQLITE_MISUSE    => "Library used incorrectly",
        SQLITE_NOLFS     => "Uses OS features not supported on host",
        SQLITE_AUTH      => "Authorization denied",
        SQLITE_FORMAT    => "Auxiliary database format error",
        SQLITE_RANGE     => "2nd parameter to sqlite3_bind out of range",
        SQLITE_NOTADB    => "File opened that is not a database file",
        SQLITE_NOTICE    => "Notifications from sqlite3_log()",
        SQLITE_WARNING   => "Warnings from sqlite3_log()",
        SQLITE_ROW       => "sqlite3_step() has another row ready",
        SQLITE_DONE      => "sqlite3_step() has finished executing",
        _                => "Unknown error code",
    }
}

pub const SQLITE_CONFIG_LOG  : c_int = 16;
pub const SQLITE_UTF8  : c_int = 1;
pub const SQLITE_DETERMINISTIC  : c_int = 0x800;
<commit_msg>Add extended result codes to libsqlite3-sys<commit_after>// bindgen.rs was created with bindgen 0.15.0 against sqlite3 3.8.10

#![allow(non_snake_case)]

extern crate libc;

pub use self::bindgen::*;

use std::mem;
use libc::c_int;

mod bindgen;

// Result codes.

pub const SQLITE_OK        : c_int =   0;
pub const SQLITE_ERROR     : c_int =   1;
pub const SQLITE_INTERNAL  : c_int =   2;
pub const SQLITE_PERM      : c_int =   3;
pub const SQLITE_ABORT     : c_int =   4;
pub const SQLITE_BUSY      : c_int =   5;
pub const SQLITE_LOCKED    : c_int =   6;
pub const SQLITE_NOMEM     : c_int =   7;
pub const SQLITE_READONLY  : c_int =   8;
pub const SQLITE_INTERRUPT : c_int =   9;
pub const SQLITE_IOERR     : c_int =  10;
pub const SQLITE_CORRUPT   : c_int =  11;
pub const SQLITE_NOTFOUND  : c_int =  12;
pub const SQLITE_FULL      : c_int =  13;
pub const SQLITE_CANTOPEN  : c_int =  14;
pub const SQLITE_PROTOCOL  : c_int =  15;
pub const SQLITE_EMPTY     : c_int =  16;
pub const SQLITE_SCHEMA    : c_int =  17;
pub const SQLITE_TOOBIG    : c_int =  18;
pub const SQLITE_CONSTRAINT: c_int =  19;
pub const SQLITE_MISMATCH  : c_int =  20;
pub const SQLITE_MISUSE    : c_int =  21;
pub const SQLITE_NOLFS     : c_int =  22;
pub const SQLITE_AUTH      : c_int =  23;
pub const SQLITE_FORMAT    : c_int =  24;
pub const SQLITE_RANGE     : c_int =  25;
pub const SQLITE_NOTADB    : c_int =  26;
pub const SQLITE_NOTICE    : c_int =  27;
pub const SQLITE_WARNING   : c_int =  28;
pub const SQLITE_ROW       : c_int = 100;
pub const SQLITE_DONE      : c_int = 101;

// Extended result codes.

pub const SQLITE_IOERR_READ              : c_int = (SQLITE_IOERR | (1<<8));
pub const SQLITE_IOERR_SHORT_READ        : c_int = (SQLITE_IOERR | (2<<8));
pub const SQLITE_IOERR_WRITE             : c_int = (SQLITE_IOERR | (3<<8));
pub const SQLITE_IOERR_FSYNC             : c_int = (SQLITE_IOERR | (4<<8));
pub const SQLITE_IOERR_DIR_FSYNC         : c_int = (SQLITE_IOERR | (5<<8));
pub const SQLITE_IOERR_TRUNCATE          : c_int = (SQLITE_IOERR | (6<<8));
pub const SQLITE_IOERR_FSTAT             : c_int = (SQLITE_IOERR | (7<<8));
pub const SQLITE_IOERR_UNLOCK            : c_int = (SQLITE_IOERR | (8<<8));
pub const SQLITE_IOERR_RDLOCK            : c_int = (SQLITE_IOERR | (9<<8));
pub const SQLITE_IOERR_DELETE            : c_int = (SQLITE_IOERR | (10<<8));
pub const SQLITE_IOERR_BLOCKED           : c_int = (SQLITE_IOERR | (11<<8));
pub const SQLITE_IOERR_NOMEM             : c_int = (SQLITE_IOERR | (12<<8));
pub const SQLITE_IOERR_ACCESS            : c_int = (SQLITE_IOERR | (13<<8));
pub const SQLITE_IOERR_CHECKRESERVEDLOCK : c_int = (SQLITE_IOERR | (14<<8));
pub const SQLITE_IOERR_LOCK              : c_int = (SQLITE_IOERR | (15<<8));
pub const SQLITE_IOERR_CLOSE             : c_int = (SQLITE_IOERR | (16<<8));
pub const SQLITE_IOERR_DIR_CLOSE         : c_int = (SQLITE_IOERR | (17<<8));
pub const SQLITE_IOERR_SHMOPEN           : c_int = (SQLITE_IOERR | (18<<8));
pub const SQLITE_IOERR_SHMSIZE           : c_int = (SQLITE_IOERR | (19<<8));
pub const SQLITE_IOERR_SHMLOCK           : c_int = (SQLITE_IOERR | (20<<8));
pub const SQLITE_IOERR_SHMMAP            : c_int = (SQLITE_IOERR | (21<<8));
pub const SQLITE_IOERR_SEEK              : c_int = (SQLITE_IOERR | (22<<8));
pub const SQLITE_IOERR_DELETE_NOENT      : c_int = (SQLITE_IOERR | (23<<8));
pub const SQLITE_IOERR_MMAP              : c_int = (SQLITE_IOERR | (24<<8));
pub const SQLITE_IOERR_GETTEMPPATH       : c_int = (SQLITE_IOERR | (25<<8));
pub const SQLITE_IOERR_CONVPATH          : c_int = (SQLITE_IOERR | (26<<8));
pub const SQLITE_IOERR_VNODE             : c_int = (SQLITE_IOERR | (27<<8));
pub const SQLITE_LOCKED_SHAREDCACHE      : c_int = (SQLITE_LOCKED |  (1<<8));
pub const SQLITE_BUSY_RECOVERY           : c_int = (SQLITE_BUSY   |  (1<<8));
pub const SQLITE_BUSY_SNAPSHOT           : c_int = (SQLITE_BUSY   |  (2<<8));
pub const SQLITE_CANTOPEN_NOTEMPDIR      : c_int = (SQLITE_CANTOPEN | (1<<8));
pub const SQLITE_CANTOPEN_ISDIR          : c_int = (SQLITE_CANTOPEN | (2<<8));
pub const SQLITE_CANTOPEN_FULLPATH       : c_int = (SQLITE_CANTOPEN | (3<<8));
pub const SQLITE_CANTOPEN_CONVPATH       : c_int = (SQLITE_CANTOPEN | (4<<8));
pub const SQLITE_CORRUPT_VTAB            : c_int = (SQLITE_CORRUPT | (1<<8));
pub const SQLITE_READONLY_RECOVERY       : c_int = (SQLITE_READONLY | (1<<8));
pub const SQLITE_READONLY_CANTLOCK       : c_int = (SQLITE_READONLY | (2<<8));
pub const SQLITE_READONLY_ROLLBACK       : c_int = (SQLITE_READONLY | (3<<8));
pub const SQLITE_READONLY_DBMOVED        : c_int = (SQLITE_READONLY | (4<<8));
pub const SQLITE_ABORT_ROLLBACK          : c_int = (SQLITE_ABORT | (2<<8));
pub const SQLITE_CONSTRAINT_CHECK        : c_int = (SQLITE_CONSTRAINT | (1<<8));
pub const SQLITE_CONSTRAINT_COMMITHOOK   : c_int = (SQLITE_CONSTRAINT | (2<<8));
pub const SQLITE_CONSTRAINT_FOREIGNKEY   : c_int = (SQLITE_CONSTRAINT | (3<<8));
pub const SQLITE_CONSTRAINT_FUNCTION     : c_int = (SQLITE_CONSTRAINT | (4<<8));
pub const SQLITE_CONSTRAINT_NOTNULL      : c_int = (SQLITE_CONSTRAINT | (5<<8));
pub const SQLITE_CONSTRAINT_PRIMARYKEY   : c_int = (SQLITE_CONSTRAINT | (6<<8));
pub const SQLITE_CONSTRAINT_TRIGGER      : c_int = (SQLITE_CONSTRAINT | (7<<8));
pub const SQLITE_CONSTRAINT_UNIQUE       : c_int = (SQLITE_CONSTRAINT | (8<<8));
pub const SQLITE_CONSTRAINT_VTAB         : c_int = (SQLITE_CONSTRAINT | (9<<8));
pub const SQLITE_CONSTRAINT_ROWID        : c_int = (SQLITE_CONSTRAINT |(10<<8));
pub const SQLITE_NOTICE_RECOVER_WAL      : c_int = (SQLITE_NOTICE | (1<<8));
pub const SQLITE_NOTICE_RECOVER_ROLLBACK : c_int = (SQLITE_NOTICE | (2<<8));
pub const SQLITE_WARNING_AUTOINDEX       : c_int = (SQLITE_WARNING | (1<<8));
pub const SQLITE_AUTH_USER               : c_int = (SQLITE_AUTH | (1<<8));

// SQLite datatype constants.
pub const SQLITE_INTEGER : c_int = 1;
pub const SQLITE_FLOAT   : c_int = 2;
pub const SQLITE_TEXT    : c_int = 3;
pub const SQLITE_BLOB    : c_int = 4;
pub const SQLITE_NULL    : c_int = 5;

pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(0isize) })
}

pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
    Some(unsafe { mem::transmute(-1isize) })
}

pub fn code_to_str(code: c_int) -> &'static str {
    match code {
        SQLITE_OK        => "Successful result",
        SQLITE_ERROR     => "SQL error or missing database",
        SQLITE_INTERNAL  => "Internal logic error in SQLite",
        SQLITE_PERM      => "Access permission denied",
        SQLITE_ABORT     => "Callback routine requested an abort",
        SQLITE_BUSY      => "The database file is locked",
        SQLITE_LOCKED    => "A table in the database is locked",
        SQLITE_NOMEM     => "A malloc() failed",
        SQLITE_READONLY  => "Attempt to write a readonly database",
        SQLITE_INTERRUPT => "Operation terminated by sqlite3_interrupt()",
        SQLITE_IOERR     => "Some kind of disk I/O error occurred",
        SQLITE_CORRUPT   => "The database disk image is malformed",
        SQLITE_NOTFOUND  => "Unknown opcode in sqlite3_file_control()",
        SQLITE_FULL      => "Insertion failed because database is full",
        SQLITE_CANTOPEN  => "Unable to open the database file",
        SQLITE_PROTOCOL  => "Database lock protocol error",
        SQLITE_EMPTY     => "Database is empty",
        SQLITE_SCHEMA    => "The database schema changed",
        SQLITE_TOOBIG    => "String or BLOB exceeds size limit",
        SQLITE_CONSTRAINT=> "Abort due to constraint violation",
        SQLITE_MISMATCH  => "Data type mismatch",
        SQLITE_MISUSE    => "Library used incorrectly",
        SQLITE_NOLFS     => "Uses OS features not supported on host",
        SQLITE_AUTH      => "Authorization denied",
        SQLITE_FORMAT    => "Auxiliary database format error",
        SQLITE_RANGE     => "2nd parameter to sqlite3_bind out of range",
        SQLITE_NOTADB    => "File opened that is not a database file",
        SQLITE_NOTICE    => "Notifications from sqlite3_log()",
        SQLITE_WARNING   => "Warnings from sqlite3_log()",
        SQLITE_ROW       => "sqlite3_step() has another row ready",
        SQLITE_DONE      => "sqlite3_step() has finished executing",

        SQLITE_IOERR_READ              => "Error reading from disk",
        SQLITE_IOERR_SHORT_READ        => "Unable to obtain number of requested bytes (file truncated?)",
        SQLITE_IOERR_WRITE             => "Error writing to disk",
        SQLITE_IOERR_FSYNC             => "Error flushing data to persistent storage (fsync)",
        SQLITE_IOERR_DIR_FSYNC         => "Error calling fsync on a directory",
        SQLITE_IOERR_TRUNCATE          => "Error attempting to truncate file",
        SQLITE_IOERR_FSTAT             => "Error invoking fstat to get file metadata",
        SQLITE_IOERR_UNLOCK            => "I/O error within xUnlock of a VFS object",
        SQLITE_IOERR_RDLOCK            => "I/O error within xLock of a VFS object (trying to obtain a read lock)",
        SQLITE_IOERR_DELETE            => "I/O error within xDelete of a VFS object",
        SQLITE_IOERR_BLOCKED           => "SQLITE_IOERR_BLOCKED", // no longer used
        SQLITE_IOERR_NOMEM             => "Out of memory in I/O layer",
        SQLITE_IOERR_ACCESS            => "I/O error within xAccess of a VFS object",
        SQLITE_IOERR_CHECKRESERVEDLOCK => "I/O error within then xCheckReservedLock method",
        SQLITE_IOERR_LOCK              => "I/O error in the advisory file locking layer",
        SQLITE_IOERR_CLOSE             => "I/O error within the xClose method",
        SQLITE_IOERR_DIR_CLOSE         => "SQLITE_IOERR_DIR_CLOSE", // no longer used
        SQLITE_IOERR_SHMOPEN           => "I/O error within the xShmMap method (trying to open a new shared-memory segment)",
        SQLITE_IOERR_SHMSIZE           => "I/O error within the xShmMap method (trying to resize an existing shared-memory segment)",
        SQLITE_IOERR_SHMLOCK           => "SQLITE_IOERR_SHMLOCK", // no longer used
        SQLITE_IOERR_SHMMAP            => "I/O error within the xShmMap method (trying to map a shared-memory segment into process address space)",
        SQLITE_IOERR_SEEK              => "I/O error within the xRead or xWrite (trying to seek within a file)",
        SQLITE_IOERR_DELETE_NOENT      => "File being deleted does not exist",
        SQLITE_IOERR_MMAP              => "I/O error while trying to map or unmap part of the database file into process address space",
        SQLITE_IOERR_GETTEMPPATH       => "VFS is unable to determine a suitable directory for temporary files",
        SQLITE_IOERR_CONVPATH          => "cygwin_conv_path() system call failed",
        SQLITE_IOERR_VNODE             => "SQLITE_IOERR_VNODE", // not documented?
        SQLITE_LOCKED_SHAREDCACHE      => "Locking conflict due to another connection with a shared cache",
        SQLITE_BUSY_RECOVERY           => "Another process is recovering a WAL mode database file",
        SQLITE_BUSY_SNAPSHOT           => "Cannot promote read transaction to write transaction because of writes by another connection",
        SQLITE_CANTOPEN_NOTEMPDIR      => "SQLITE_CANTOPEN_NOTEMPDIR", // no longer used
        SQLITE_CANTOPEN_ISDIR          => "Attempted to open directory as file",
        SQLITE_CANTOPEN_FULLPATH       => "Unable to convert filename into full pathname",
        SQLITE_CANTOPEN_CONVPATH       => "cygwin_conv_path() system call failed",
        SQLITE_CORRUPT_VTAB            => "Content in the virtual table is corrupt",
        SQLITE_READONLY_RECOVERY       => "WAL mode database file needs recovery (requires write access)",
        SQLITE_READONLY_CANTLOCK       => "Shared-memory file associated with WAL mode database is read-only",
        SQLITE_READONLY_ROLLBACK       => "Database has hot journal that must be rolled back (requires write access)",
        SQLITE_READONLY_DBMOVED        => "Database cannot be modified because database file has moved",
        SQLITE_ABORT_ROLLBACK          => "Transaction was rolled back",
        SQLITE_CONSTRAINT_CHECK        => "A CHECK constraint failed",
        SQLITE_CONSTRAINT_COMMITHOOK   => "Commit hook caused rollback",
        SQLITE_CONSTRAINT_FOREIGNKEY   => "Foreign key constraint failed",
        SQLITE_CONSTRAINT_FUNCTION     => "Error returned from extension function",
        SQLITE_CONSTRAINT_NOTNULL      => "A NOT NULL constraint failed",
        SQLITE_CONSTRAINT_PRIMARYKEY   => "A PRIMARY KEY constraint failed",
        SQLITE_CONSTRAINT_TRIGGER      => "A RAISE function within a trigger fired",
        SQLITE_CONSTRAINT_UNIQUE       => "A UNIQUE constraint failed",
        SQLITE_CONSTRAINT_VTAB         => "An application-defined virtual table error occurred",
        SQLITE_CONSTRAINT_ROWID        => "A non-unique rowid occurred",
        SQLITE_NOTICE_RECOVER_WAL      => "A WAL mode database file was recovered",
        SQLITE_NOTICE_RECOVER_ROLLBACK => "Hot journal was rolled back",
        SQLITE_WARNING_AUTOINDEX       => "Automatic indexing used - database might benefit from additional indexes",
        SQLITE_AUTH_USER               => "SQLITE_AUTH_USER", // not documented?

        _ => "Unknown error code",
    }
}

pub const SQLITE_CONFIG_LOG  : c_int = 16;
pub const SQLITE_UTF8  : c_int = 1;
pub const SQLITE_DETERMINISTIC  : c_int = 0x800;
<|endoftext|>


<commit_before>use std::cmp::{max, min};

use ra_db::{SyntaxDatabase, Cancelable};
use ra_syntax::{
    AstNode, SyntaxNode, TextUnit, TextRange,
    SyntaxKind::FN_DEF,
    ast::{self, ArgListOwner, DocCommentsOwner},
};
use ra_editor::find_node_at_offset;

use crate::{FilePosition, CallInfo, db::RootDatabase};

pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> {
    let (sig_info, active_parameter) = ctry!(signature_and_active_param(db, position)?);
    let res = CallInfo {
        label: sig_info.label,
        doc: sig_info.doc,
        parameters: sig_info.params,
        active_parameter,
    };
    Ok(Some(res))
}

/// Computes parameter information for the given call expression.
fn signature_and_active_param(
    db: &RootDatabase,
    position: FilePosition,
) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
    let file = db.source_file(position.file_id);
    let syntax = file.syntax();

    // Find the calling expression and it's NameRef
    let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset));
    let name_ref = ctry!(calling_node.name_ref());

    // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
    let file_symbols = db.index_resolve(name_ref)?;
    for symbol in file_symbols {
        if symbol.ptr.kind() == FN_DEF {
            let fn_file = db.source_file(symbol.file_id);
            let fn_def = symbol.ptr.resolve(&fn_file);
            let fn_def = ast::FnDef::cast(&fn_def).unwrap();
            if let Some(descriptor) = FnSignatureInfo::new(fn_def) {
                // If we have a calling expression let's find which argument we are on
                let mut current_parameter = None;

                let num_params = descriptor.params.len();
                let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();

                if num_params == 1 {
                    if !has_self {
                        current_parameter = Some(0);
                    }
                } else if num_params > 1 {
                    // Count how many parameters into the call we are.
                    // TODO: This is best effort for now and should be fixed at some point.
                    // It may be better to see where we are in the arg_list and then check
                    // where offset is in that list (or beyond).
                    // Revisit this after we get documentation comments in.
                    if let Some(ref arg_list) = calling_node.arg_list() {
                        let start = arg_list.syntax().range().start();

                        let range_search = TextRange::from_to(start, position.offset);
                        let mut commas: usize = arg_list
                            .syntax()
                            .text()
                            .slice(range_search)
                            .to_string()
                            .matches(',')
                            .count();

                        // If we have a method call eat the first param since it's just self.
                        if has_self {
                            commas += 1;
                        }

                        current_parameter = Some(commas);
                    }
                }

                return Ok(Some((descriptor, current_parameter)));
            }
        }
    }

    Ok(None)
}

enum FnCallNode<'a> {
    CallExpr(&'a ast::CallExpr),
    MethodCallExpr(&'a ast::MethodCallExpr),
}

impl<'a> FnCallNode<'a> {
    pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option<FnCallNode<'a>> {
        if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
            return Some(FnCallNode::CallExpr(expr));
        }
        if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
            return Some(FnCallNode::MethodCallExpr(expr));
        }
        None
    }

    pub fn name_ref(&self) -> Option<&'a ast::NameRef> {
        match *self {
            FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()?.kind() {
                ast::ExprKind::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
                _ => return None,
            }),

            FnCallNode::MethodCallExpr(call_expr) => call_expr
                .syntax()
                .children()
                .filter_map(ast::NameRef::cast)
                .nth(0),
        }
    }

    pub fn arg_list(&self) -> Option<&'a ast::ArgList> {
        match *self {
            FnCallNode::CallExpr(expr) => expr.arg_list(),
            FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
        }
    }
}

#[derive(Debug, Clone)]
struct FnSignatureInfo {
    label: String,
    params: Vec<String>,
    doc: Option<String>,
}

impl FnSignatureInfo {
    fn new(node: &ast::FnDef) -> Option<Self> {
        let mut doc = None;

        // Strip the body out for the label.
        let mut label: String = if let Some(body) = node.body() {
            let body_range = body.syntax().range();
            let label: String = node
                .syntax()
                .children()
                .filter(|child| !child.range().is_subrange(&body_range))
                .map(|node| node.text().to_string())
                .collect();
            label
        } else {
            node.syntax().text().to_string()
        };

        if let Some((comment_range, docs)) = FnSignatureInfo::extract_doc_comments(node) {
            let comment_range = comment_range
                .checked_sub(node.syntax().range().start())
                .unwrap();
            let start = comment_range.start().to_usize();
            let end = comment_range.end().to_usize();

            // Remove the comment from the label
            label.replace_range(start..end, "");

            // Massage markdown
            let mut processed_lines = Vec::new();
            let mut in_code_block = false;
            for line in docs.lines() {
                if line.starts_with("```") {
                    in_code_block = !in_code_block;
                }

                let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
                    "```rust".into()
                } else {
                    line.to_string()
                };

                processed_lines.push(line);
            }

            if !processed_lines.is_empty() {
                doc = Some(processed_lines.join("\n"));
            }
        }

        let params = FnSignatureInfo::param_list(node);

        Some(FnSignatureInfo {
            params,
            label: label.trim().to_owned(),
            doc,
        })
    }

    fn extract_doc_comments(node: &ast::FnDef) -> Option<(TextRange, String)> {
        if node.doc_comments().count() == 0 {
            return None;
        }

        let comment_text = node.doc_comment_text();

        let (begin, end) = node
            .doc_comments()
            .map(|comment| comment.syntax().range())
            .map(|range| (range.start().to_usize(), range.end().to_usize()))
            .fold((std::usize::MAX, std::usize::MIN), |acc, range| {
                (min(acc.0, range.0), max(acc.1, range.1))
            });

        let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));

        Some((range, comment_text))
    }

    fn param_list(node: &ast::FnDef) -> Vec<String> {
        let mut res = vec![];
        if let Some(param_list) = node.param_list() {
            if let Some(self_param) = param_list.self_param() {
                res.push(self_param.syntax().text().to_string())
            }

            // Maybe use param.pat here? See if we can just extract the name?
            //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
            res.extend(
                param_list
                    .params()
                    .filter_map(|p| p.pat())
                    .map(|pat| pat.syntax().text().to_string()),
            );
        }
        res
    }
}

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

    use crate::mock_analysis::single_file_with_position;

    fn call_info(text: &str) -> CallInfo {
        let (analysis, position) = single_file_with_position(text);
        analysis.call_info(position).unwrap().unwrap()
    }

    #[test]
    fn test_fn_signature_two_args_first() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string()));
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_second() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(3, <|>); }"#,
        );

        assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string()));
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_for_impl() {
        let info = call_info(
            r#"struct F; impl F { pub fn new() { F{}} }
fn bar() {let _ : F = F::new(<|>);}"#,
        );

        assert_eq!(info.parameters, Vec::<String>::new());
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_self() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["&self".to_string()]);
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_with_arg() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self, x: i32) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["&self".to_string(), "x".to_string()]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_with_docs_simple() {
        let info = call_info(
            r#"
/// test
// non-doc-comment
fn foo(j: u32) -> u32 {
    j
}

fn bar() {
    let _ = foo(<|>);
}
"#,
        );

        assert_eq!(info.parameters, vec!["j".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string());
        assert_eq!(info.doc, Some("test".into()));
    }

    #[test]
    fn test_fn_signature_with_docs() {
        let info = call_info(
            r#"
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

pub fn do() {
    add_one(<|>
}"#,
        );

        assert_eq!(info.parameters, vec!["x".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
        assert_eq!(
            info.doc,
            Some(
                r#"Adds one to the number given.

# Examples

```rust
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .into()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_impl() {
        let info = call_info(
            r#"
struct addr;
impl addr {
    /// Adds one to the number given.
    ///
    /// # Examples
    ///
    /// ```
    /// let five = 5;
    ///
    /// assert_eq!(6, my_crate::add_one(5));
    /// ```
    pub fn add_one(x: i32) -> i32 {
        x + 1
    }
}

pub fn do_it() {
    addr {};
    addr::add_one(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["x".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
        assert_eq!(
            info.doc,
            Some(
                r#"Adds one to the number given.

# Examples

```rust
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .into()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_from_actix() {
        let info = call_info(
            r#"
pub trait WriteHandler<E>
where
    Self: Actor,
    Self::Context: ActorContext,
{
    /// Method is called when writer emits error.
    ///
    /// If this method returns `ErrorAction::Continue` writer processing
    /// continues otherwise stream processing stops.
    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
        Running::Stop
    }

    /// Method is called when writer finishes.
    ///
    /// By default this method stops actor's `Context`.
    fn finished(&mut self, ctx: &mut Self::Context) {
        ctx.stop()
    }
}

pub fn foo() {
    WriteHandler r;
    r.finished(<|>);
}

"#,
        );

        assert_eq!(
            info.parameters,
            vec!["&mut self".to_string(), "ctx".to_string()]
        );
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(
            info.doc,
            Some(
                r#"Method is called when writer finishes.

By default this method stops actor's `Context`."#
                    .into()
            )
        );
    }

}
<commit_msg>kill FnSignatureInfo<commit_after>use std::cmp::{max, min};

use ra_db::{SyntaxDatabase, Cancelable};
use ra_syntax::{
    AstNode, SyntaxNode, TextUnit, TextRange,
    SyntaxKind::FN_DEF,
    ast::{self, ArgListOwner, DocCommentsOwner},
};
use ra_editor::find_node_at_offset;

use crate::{FilePosition, CallInfo, db::RootDatabase};

/// Computes parameter information for the given call expression.
pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> {
    let file = db.source_file(position.file_id);
    let syntax = file.syntax();

    // Find the calling expression and it's NameRef
    let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset));
    let name_ref = ctry!(calling_node.name_ref());

    // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
    let file_symbols = db.index_resolve(name_ref)?;
    for symbol in file_symbols {
        if symbol.ptr.kind() == FN_DEF {
            let fn_file = db.source_file(symbol.file_id);
            let fn_def = symbol.ptr.resolve(&fn_file);
            let fn_def = ast::FnDef::cast(&fn_def).unwrap();
            if let Some(mut call_info) = CallInfo::new(fn_def) {
                // If we have a calling expression let's find which argument we are on
                let num_params = call_info.parameters.len();
                let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();

                if num_params == 1 {
                    if !has_self {
                        call_info.active_parameter = Some(0);
                    }
                } else if num_params > 1 {
                    // Count how many parameters into the call we are.
                    // TODO: This is best effort for now and should be fixed at some point.
                    // It may be better to see where we are in the arg_list and then check
                    // where offset is in that list (or beyond).
                    // Revisit this after we get documentation comments in.
                    if let Some(ref arg_list) = calling_node.arg_list() {
                        let start = arg_list.syntax().range().start();

                        let range_search = TextRange::from_to(start, position.offset);
                        let mut commas: usize = arg_list
                            .syntax()
                            .text()
                            .slice(range_search)
                            .to_string()
                            .matches(',')
                            .count();

                        // If we have a method call eat the first param since it's just self.
                        if has_self {
                            commas += 1;
                        }

                        call_info.active_parameter = Some(commas);
                    }
                }

                return Ok(Some(call_info));
            }
        }
    }

    Ok(None)
}

enum FnCallNode<'a> {
    CallExpr(&'a ast::CallExpr),
    MethodCallExpr(&'a ast::MethodCallExpr),
}

impl<'a> FnCallNode<'a> {
    pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option<FnCallNode<'a>> {
        if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
            return Some(FnCallNode::CallExpr(expr));
        }
        if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
            return Some(FnCallNode::MethodCallExpr(expr));
        }
        None
    }

    pub fn name_ref(&self) -> Option<&'a ast::NameRef> {
        match *self {
            FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()?.kind() {
                ast::ExprKind::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
                _ => return None,
            }),

            FnCallNode::MethodCallExpr(call_expr) => call_expr
                .syntax()
                .children()
                .filter_map(ast::NameRef::cast)
                .nth(0),
        }
    }

    pub fn arg_list(&self) -> Option<&'a ast::ArgList> {
        match *self {
            FnCallNode::CallExpr(expr) => expr.arg_list(),
            FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
        }
    }
}

impl CallInfo {
    fn new(node: &ast::FnDef) -> Option<Self> {
        let mut doc = None;

        // Strip the body out for the label.
        let mut label: String = if let Some(body) = node.body() {
            let body_range = body.syntax().range();
            let label: String = node
                .syntax()
                .children()
                .filter(|child| !child.range().is_subrange(&body_range))
                .map(|node| node.text().to_string())
                .collect();
            label
        } else {
            node.syntax().text().to_string()
        };

        if let Some((comment_range, docs)) = CallInfo::extract_doc_comments(node) {
            let comment_range = comment_range
                .checked_sub(node.syntax().range().start())
                .unwrap();
            let start = comment_range.start().to_usize();
            let end = comment_range.end().to_usize();

            // Remove the comment from the label
            label.replace_range(start..end, "");

            // Massage markdown
            let mut processed_lines = Vec::new();
            let mut in_code_block = false;
            for line in docs.lines() {
                if line.starts_with("```") {
                    in_code_block = !in_code_block;
                }

                let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
                    "```rust".into()
                } else {
                    line.to_string()
                };

                processed_lines.push(line);
            }

            if !processed_lines.is_empty() {
                doc = Some(processed_lines.join("\n"));
            }
        }

        Some(CallInfo {
            parameters: CallInfo::param_list(node),
            label: label.trim().to_owned(),
            doc,
            active_parameter: None,
        })
    }

    fn extract_doc_comments(node: &ast::FnDef) -> Option<(TextRange, String)> {
        if node.doc_comments().count() == 0 {
            return None;
        }

        let comment_text = node.doc_comment_text();

        let (begin, end) = node
            .doc_comments()
            .map(|comment| comment.syntax().range())
            .map(|range| (range.start().to_usize(), range.end().to_usize()))
            .fold((std::usize::MAX, std::usize::MIN), |acc, range| {
                (min(acc.0, range.0), max(acc.1, range.1))
            });

        let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));

        Some((range, comment_text))
    }

    fn param_list(node: &ast::FnDef) -> Vec<String> {
        let mut res = vec![];
        if let Some(param_list) = node.param_list() {
            if let Some(self_param) = param_list.self_param() {
                res.push(self_param.syntax().text().to_string())
            }

            // Maybe use param.pat here? See if we can just extract the name?
            //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
            res.extend(
                param_list
                    .params()
                    .filter_map(|p| p.pat())
                    .map(|pat| pat.syntax().text().to_string()),
            );
        }
        res
    }
}

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

    use crate::mock_analysis::single_file_with_position;

    fn call_info(text: &str) -> CallInfo {
        let (analysis, position) = single_file_with_position(text);
        analysis.call_info(position).unwrap().unwrap()
    }

    #[test]
    fn test_fn_signature_two_args_first() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string()));
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_second() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(3, <|>); }"#,
        );

        assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string()));
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_for_impl() {
        let info = call_info(
            r#"struct F; impl F { pub fn new() { F{}} }
fn bar() {let _ : F = F::new(<|>);}"#,
        );

        assert_eq!(info.parameters, Vec::<String>::new());
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_self() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["&self".to_string()]);
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_with_arg() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self, x: i32) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["&self".to_string(), "x".to_string()]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_with_docs_simple() {
        let info = call_info(
            r#"
/// test
// non-doc-comment
fn foo(j: u32) -> u32 {
    j
}

fn bar() {
    let _ = foo(<|>);
}
"#,
        );

        assert_eq!(info.parameters, vec!["j".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string());
        assert_eq!(info.doc, Some("test".into()));
    }

    #[test]
    fn test_fn_signature_with_docs() {
        let info = call_info(
            r#"
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

pub fn do() {
    add_one(<|>
}"#,
        );

        assert_eq!(info.parameters, vec!["x".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
        assert_eq!(
            info.doc,
            Some(
                r#"Adds one to the number given.

# Examples

```rust
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .into()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_impl() {
        let info = call_info(
            r#"
struct addr;
impl addr {
    /// Adds one to the number given.
    ///
    /// # Examples
    ///
    /// ```
    /// let five = 5;
    ///
    /// assert_eq!(6, my_crate::add_one(5));
    /// ```
    pub fn add_one(x: i32) -> i32 {
        x + 1
    }
}

pub fn do_it() {
    addr {};
    addr::add_one(<|>);
}"#,
        );

        assert_eq!(info.parameters, vec!["x".to_string()]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
        assert_eq!(
            info.doc,
            Some(
                r#"Adds one to the number given.

# Examples

```rust
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .into()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_from_actix() {
        let info = call_info(
            r#"
pub trait WriteHandler<E>
where
    Self: Actor,
    Self::Context: ActorContext,
{
    /// Method is called when writer emits error.
    ///
    /// If this method returns `ErrorAction::Continue` writer processing
    /// continues otherwise stream processing stops.
    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
        Running::Stop
    }

    /// Method is called when writer finishes.
    ///
    /// By default this method stops actor's `Context`.
    fn finished(&mut self, ctx: &mut Self::Context) {
        ctx.stop()
    }
}

pub fn foo() {
    WriteHandler r;
    r.finished(<|>);
}

"#,
        );

        assert_eq!(
            info.parameters,
            vec!["&mut self".to_string(), "ctx".to_string()]
        );
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(
            info.doc,
            Some(
                r#"Method is called when writer finishes.

By default this method stops actor's `Context`."#
                    .into()
            )
        );
    }

}
<|endoftext|>


<commit_before>extern crate openzwave;
extern crate foxbox_adapters as adapters;
extern crate foxbox_taxonomy as taxonomy;
extern crate transformable_channels;

use taxonomy::util::Id as TaxId;
use taxonomy::services::{ AdapterId, Getter, Setter };
use taxonomy::values::{ Value, Range };
use taxonomy::api::{ ResultMap, Error as TaxError };
use adapters::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent };
use transformable_channels::mpsc::ExtSender;

struct OpenzwaveAdapter {
    name: String,
    vendor: String,
    version: [u32; 4],
    manager: Box<AdapterManagerHandle + Send>
}

impl OpenzwaveAdapter {
    fn init<T: AdapterManagerHandle + Clone + Send + 'static> (manager: &T) -> Result<(), TaxError> {
        let adapter = Box::new(OpenzwaveAdapter {
            name: String::from("OpenZwave Adapter"),
            vendor: String::from("Mozilla"),
            version: [1, 0, 0, 0],
            manager: Box::new(manager.clone())
        });

        try!(manager.add_adapter(adapter));

        Ok(())
    }
}

impl adapters::adapter::Adapter for OpenzwaveAdapter {
    fn id(&self) -> TaxId<AdapterId> {
        unimplemented!()
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn vendor(&self) -> &str {
        &self.vendor
    }

    fn version(&self) -> &[u32; 4] {
        &self.version
    }

    fn fetch_values(&self, set: Vec<TaxId<Getter>>) -> ResultMap<TaxId<Getter>, Option<Value>, TaxError> {
        unimplemented!()
    }

    fn send_values(&self, values: Vec<(TaxId<Setter>, Value)>) -> ResultMap<TaxId<Setter>, (), TaxError> {
        unimplemented!()
    }

    fn register_watch(&self, values: Vec<(TaxId<Getter>, Option<Range>)>, cb: Box<ExtSender<WatchEvent>>) -> ResultMap<TaxId<Getter>, Box<AdapterWatchGuard>, TaxError> {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>[fxbox/openzwave-adapter] add the id impl<commit_after>extern crate openzwave;
extern crate foxbox_adapters as adapters;
extern crate foxbox_taxonomy as taxonomy;
extern crate transformable_channels;

use taxonomy::util::Id as TaxId;
use taxonomy::services::{ AdapterId, Getter, Setter };
use taxonomy::values::{ Value, Range };
use taxonomy::api::{ ResultMap, Error as TaxError };
use adapters::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent };
use transformable_channels::mpsc::ExtSender;

struct OpenzwaveAdapter {
    id: TaxId<AdapterId>,
    name: String,
    vendor: String,
    version: [u32; 4],
    manager: Box<AdapterManagerHandle + Send>
}

impl OpenzwaveAdapter {
    fn init<T: AdapterManagerHandle + Clone + Send + 'static> (manager: &T) -> Result<(), TaxError> {
        let name = String::from("OpenZwave Adapter");
        let adapter = Box::new(OpenzwaveAdapter {
            id: TaxId::new(name.clone()), // replace with &name once we update to latest taxonomy
            name: name,
            vendor: String::from("Mozilla"),
            version: [1, 0, 0, 0],
            manager: Box::new(manager.clone())
        });

        try!(manager.add_adapter(adapter));

        Ok(())
    }
}

impl adapters::adapter::Adapter for OpenzwaveAdapter {
    fn id(&self) -> TaxId<AdapterId> {
        self.id.clone()
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn vendor(&self) -> &str {
        &self.vendor
    }

    fn version(&self) -> &[u32; 4] {
        &self.version
    }

    fn fetch_values(&self, set: Vec<TaxId<Getter>>) -> ResultMap<TaxId<Getter>, Option<Value>, TaxError> {
        unimplemented!()
    }

    fn send_values(&self, values: Vec<(TaxId<Setter>, Value)>) -> ResultMap<TaxId<Setter>, (), TaxError> {
        unimplemented!()
    }

    fn register_watch(&self, values: Vec<(TaxId<Getter>, Option<Range>)>, cb: Box<ExtSender<WatchEvent>>) -> ResultMap<TaxId<Getter>, Box<AdapterWatchGuard>, TaxError> {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use aardwolf_models::base_actor::persona::Persona;
use diesel::{pg::PgConnection, result::Error as DieselError};

use crate::{
    error::AardwolfFail,
    traits::DbAction,
    wrapper::{DbActionWrapper, Wrapped},
};

pub struct FetchPersona(pub i32);

impl Wrapped for FetchPersona {
    type Wrapper = DbActionWrapper<Self, <Self as DbAction>::Item, <Self as DbAction>::Error>;
}

impl DbAction for FetchPersona {
    type Item = Persona;
    type Error = FetchPersonaFail;

    fn db_action(self, conn: &PgConnection) -> Result<Persona, FetchPersonaFail> {
        Persona::by_id(self.0, conn).map_err(From::from)
    }
}

#[derive(Clone, Debug, Fail, Serialize)]
pub enum FetchPersonaFail {
    #[fail(display = "Error in database")]
    Database,
    #[fail(display = "Persona not found")]
    NotFound,
}

impl From<DieselError> for FetchPersonaFail {
    fn from(e: DieselError) -> Self {
        match e {
            DieselError::NotFound => FetchPersonaFail::NotFound,
            _ => FetchPersonaFail::Database,
        }
    }
}

impl AardwolfFail for FetchPersonaFail {}

#[cfg(test)]
mod tests {
    use aardwolf_models::base_actor::persona::Persona;
    use aardwolf_test_helpers::models::{
        with_base_actor, with_connection, with_persona, GenericError,
    };
    use diesel::pg::PgConnection;

    use crate::{operations::fetch_persona::FetchPersona, traits::DbAction};

    fn setup<F>(f: F)
    where
        F: FnOnce(&PgConnection, Persona) -> Result<(), GenericError>,
    {
        with_connection(|conn| {
            with_base_actor(conn, |base_actor| {
                with_persona(conn, &base_actor, |persona| f(conn, persona))
            })
        })
    }

    #[test]
    fn fetches_persona() {
        setup(|conn, persona| {
            let operation = FetchPersona(persona.id());

            assert!(operation.db_action(conn).is_ok());
            Ok(())
        })
    }

    #[test]
    fn doesnt_fetch_invalid_persona() {
        setup(|conn, persona| {
            let operation = FetchPersona(persona.id() + 1);

            assert!(operation.db_action(conn).is_ok());
            Ok(())
        })
    }
}
<commit_msg>Fix fetch persona test<commit_after>use aardwolf_models::base_actor::persona::Persona;
use diesel::{pg::PgConnection, result::Error as DieselError};

use crate::{
    error::AardwolfFail,
    traits::DbAction,
    wrapper::{DbActionWrapper, Wrapped},
};

pub struct FetchPersona(pub i32);

impl Wrapped for FetchPersona {
    type Wrapper = DbActionWrapper<Self, <Self as DbAction>::Item, <Self as DbAction>::Error>;
}

impl DbAction for FetchPersona {
    type Item = Persona;
    type Error = FetchPersonaFail;

    fn db_action(self, conn: &PgConnection) -> Result<Persona, FetchPersonaFail> {
        Persona::by_id(self.0, conn).map_err(From::from)
    }
}

#[derive(Clone, Debug, Fail, Serialize)]
pub enum FetchPersonaFail {
    #[fail(display = "Error in database")]
    Database,
    #[fail(display = "Persona not found")]
    NotFound,
}

impl From<DieselError> for FetchPersonaFail {
    fn from(e: DieselError) -> Self {
        match e {
            DieselError::NotFound => FetchPersonaFail::NotFound,
            _ => FetchPersonaFail::Database,
        }
    }
}

impl AardwolfFail for FetchPersonaFail {}

#[cfg(test)]
mod tests {
    use aardwolf_models::base_actor::persona::Persona;
    use aardwolf_test_helpers::models::{
        with_base_actor, with_connection, with_persona, GenericError,
    };
    use diesel::pg::PgConnection;

    use crate::{operations::fetch_persona::FetchPersona, traits::DbAction};

    fn setup<F>(f: F)
    where
        F: FnOnce(&PgConnection, Persona) -> Result<(), GenericError>,
    {
        with_connection(|conn| {
            with_base_actor(conn, |base_actor| {
                with_persona(conn, &base_actor, |persona| f(conn, persona))
            })
        })
    }

    #[test]
    fn fetches_persona() {
        setup(|conn, persona| {
            let operation = FetchPersona(persona.id());

            assert!(operation.db_action(conn).is_ok());
            Ok(())
        })
    }

    #[test]
    fn doesnt_fetch_invalid_persona() {
        setup(|conn, persona| {
            let operation = FetchPersona(persona.id() + 1);

            assert!(operation.db_action(conn).is_err());
            Ok(())
        })
    }
}
<|endoftext|>


<commit_before>//! `fake` contains fake implementations of Tock kernel components. Fake
//! components emulate the behavior of the real Tock kernel components, but in
//! the unit test environment. They generally have additional testing features,
//! such as error injection functionality.
//!
//! These components are exposed under the `fake` module because otherwise their
//! names would collide with the corresponding drivers (e.g. the fake Console
//! would collide with the Console driver in unit tests). Tests should generally
//! `use libtock_unittest::fake` and refer to the type with the `fake::` prefix
//! (e.g. `fake::Console`).

mod buttons;
mod gpio;
mod kernel;
mod leds;
mod low_level_debug;
mod syscall_driver;
mod syscalls;

pub use buttons::Buttons;
pub use gpio::{Gpio, GpioMode, InterruptEdge, PullMode};
pub use kernel::Kernel;
pub use leds::Leds;
pub use low_level_debug::{LowLevelDebug, Message};
pub use syscall_driver::SyscallDriver;
pub use syscalls::Syscalls;

#[cfg(test)]
mod kernel_tests;
<commit_msg>delete empty line<commit_after>//! `fake` contains fake implementations of Tock kernel components. Fake
//! components emulate the behavior of the real Tock kernel components, but in
//! the unit test environment. They generally have additional testing features,
//! such as error injection functionality.
//!
//! These components are exposed under the `fake` module because otherwise their
//! names would collide with the corresponding drivers (e.g. the fake Console
//! would collide with the Console driver in unit tests). Tests should generally
//! `use libtock_unittest::fake` and refer to the type with the `fake::` prefix
//! (e.g. `fake::Console`).

mod buttons;
mod gpio;
mod kernel;
mod leds;
mod low_level_debug;
mod syscall_driver;
mod syscalls;

pub use buttons::Buttons;
pub use gpio::{Gpio, GpioMode, InterruptEdge, PullMode};
pub use kernel::Kernel;
pub use leds::Leds;
pub use low_level_debug::{LowLevelDebug, Message};
pub use syscall_driver::SyscallDriver;
pub use syscalls::Syscalls;

#[cfg(test)]
mod kernel_tests;
<|endoftext|>


<commit_before>// Copyright (C) 2019, 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

pub mod api;
mod client;
mod error;
pub mod listener;
mod serde_helpers;

pub use client::Client;
pub use error::{Error, Result};
<commit_msg>updatehub-sdk: doc: Add doc for the crate<commit_after>// Copyright (C) 2019, 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

//! The `updatehub-sdk` crate is used to communicate with UpdateHub Agent.
//!
//! When running an agent instance, the API provides some methods
//! for communicating with UpdateHub:
//!
//! - [abort_download](Client::abort_download)
//! - [info](Client::info)
//! - [local_install](Client::local_install)
//! - [log](Client::log)
//! - [probe](Client::probe)
//! - [remote_install](Client::remote_install)

pub mod api;
mod client;
mod error;
pub mod listener;
mod serde_helpers;

pub use client::Client;
pub use error::{Error, Result};
<|endoftext|>


<commit_before>use rustc_hash::FxHashSet;

use ra_syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        if let Some(range) =
                            contiguous_range_for_comment(comment, &mut visited_comments)
                        {
                            res.push(Fold { range, kind: FoldKind::Comment })
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE_ITEM => Some(FoldKind::Imports),
        RECORD_FIELD_DEF_LIST
        | RECORD_FIELD_PAT_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK
        | MATCH_ARM_LIST
        | ENUM_VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::from_to(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        visited.insert(c.clone());
                        last = c;
                        continue;
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::from_to(
            first.syntax().text_range().start(),
            last.syntax().text_range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
        let (ranges, text) = extract_ranges(text, "fold");
        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());

        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );
        assert_eq!(
            folds.len(),
            fold_kinds.len(),
            "The amount of fold kinds is different than the expected amount"
        );
        for ((fold, range), fold_kind) in
            folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
        {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());
            assert_eq!(&fold.kind, fold_kind);
        }
    }

    #[test]
    fn test_fold_comments() {
        let text = r#"
<fold>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold>{
    <fold>// We should
    // also
    // fold
    // this one.</fold>
    <fold>//! But this one is different
    //! because it has another flavor</fold>
    <fold>/* As does this
    multiline comment */</fold>
}</fold>"#;

        let fold_kinds = &[
            FoldKind::Comment,
            FoldKind::Block,
            FoldKind::Comment,
            FoldKind::Comment,
            FoldKind::Comment,
        ];
        do_check(text, fold_kinds);
    }

    #[test]
    fn test_fold_imports() {
        let text = r#"
<fold>use std::<fold>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_mods() {
        let text = r#"

pub mod foo;
<fold>mod after_pub;
mod after_pub_next;</fold>

<fold>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_and_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

<fold>use std::collections::<fold>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Block,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_folds_macros() {
        let text = r#"
macro_rules! foo <fold>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#;

        let folds = &[FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_match_arms() {
        let text = r#"
fn main() <fold>{
    match 0 <fold>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>"#;

        let folds = &[
            FoldKind::Block,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }
}
<commit_msg>Pacify rustfmt.<commit_after>use rustc_hash::FxHashSet;

use ra_syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        if let Some(range) =
                            contiguous_range_for_comment(comment, &mut visited_comments)
                        {
                            res.push(Fold { range, kind: FoldKind::Comment })
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE_ITEM => Some(FoldKind::Imports),
        RECORD_FIELD_DEF_LIST
        | RECORD_FIELD_PAT_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK
        | MATCH_ARM_LIST
        | ENUM_VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::from_to(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        visited.insert(c.clone());
                        last = c;
                        continue;
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::from_to(
            first.syntax().text_range().start(),
            last.syntax().text_range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
        let (ranges, text) = extract_ranges(text, "fold");
        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());

        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );
        assert_eq!(
            folds.len(),
            fold_kinds.len(),
            "The amount of fold kinds is different than the expected amount"
        );
        for ((fold, range), fold_kind) in
            folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
        {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());
            assert_eq!(&fold.kind, fold_kind);
        }
    }

    #[test]
    fn test_fold_comments() {
        let text = r#"
<fold>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold>{
    <fold>// We should
    // also
    // fold
    // this one.</fold>
    <fold>//! But this one is different
    //! because it has another flavor</fold>
    <fold>/* As does this
    multiline comment */</fold>
}</fold>"#;

        let fold_kinds = &[
            FoldKind::Comment,
            FoldKind::Block,
            FoldKind::Comment,
            FoldKind::Comment,
            FoldKind::Comment,
        ];
        do_check(text, fold_kinds);
    }

    #[test]
    fn test_fold_imports() {
        let text = r#"
<fold>use std::<fold>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_mods() {
        let text = r#"

pub mod foo;
<fold>mod after_pub;
mod after_pub_next;</fold>

<fold>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_and_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

<fold>use std::collections::<fold>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Block,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_folds_macros() {
        let text = r#"
macro_rules! foo <fold>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#;

        let folds = &[FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_match_arms() {
        let text = r#"
fn main() <fold>{
    match 0 <fold>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>"#;

        let folds = &[FoldKind::Block, FoldKind::Block];
        do_check(text, folds);
    }
}
<|endoftext|>


<commit_before>use std::io;

#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		c => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[test]
fn test_sexp() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("  (  1  )  "), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("  (  (  )  )  )"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}<commit_msg>fix unused value<commit_after>#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		_ => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[test]
fn test_sexpr() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("  (  1  )  "), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("  (  (  )  )  )"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}
<|endoftext|>