<commit_before>use ra_text_edit::{AtomTextEdit};
use ra_syntax::{TextUnit, TextRange};
use crate::{LineIndex, LineCol};

#[derive(Debug)]
struct OffsetNewlineIter<'a> {
    text: &'a str,
    offset: TextUnit,
}

impl<'a> Iterator for OffsetNewlineIter<'a> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        let next_idx = self
            .text
            .char_indices()
            .filter_map(|(i, c)| if c == '\n' { Some(i + 1) } else { None })
            .next()?;
        let next = self.offset + TextUnit::from_usize(next_idx);
        self.text = &self.text[next_idx..];
        self.offset = next;
        Some(next)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum TranslatedPos {
    Before,
    After,
}

/// None means it was deleted
type TranslatedOffset = Option<(TranslatedPos, TextUnit)>;

fn translate_offset(offset: TextUnit, edit: &TranslatedAtomEdit) -> TranslatedOffset {
    if offset <= edit.delete.start() {
        Some((TranslatedPos::Before, offset))
    } else if offset <= edit.delete.end() {
        None
    } else {
        let diff = edit.insert.len() as i64 - edit.delete.len().to_usize() as i64;
        let after = TextUnit::from((offset.to_usize() as i64 + diff) as u32);
        Some((TranslatedPos::After, after))
    }
}

trait TranslatedNewlineIterator {
    fn translate(&self, offset: TextUnit) -> TextUnit;
    fn translate_range(&self, range: TextRange) -> TextRange {
        TextRange::from_to(self.translate(range.start()), self.translate(range.end()))
    }
    fn next_translated(&mut self) -> Option<TextUnit>;
    fn boxed<'a>(self) -> Box<TranslatedNewlineIterator + 'a>
    where
        Self: 'a + Sized,
    {
        Box::new(self)
    }
}

struct TranslatedAtomEdit<'a> {
    delete: TextRange,
    insert: &'a str,
}

struct TranslatedNewlines<'a, T: TranslatedNewlineIterator> {
    inner: T,
    next_inner: Option<TranslatedOffset>,
    edit: TranslatedAtomEdit<'a>,
    insert: OffsetNewlineIter<'a>,
}

impl<'a, T: TranslatedNewlineIterator> TranslatedNewlines<'a, T> {
    fn from(inner: T, edit: &'a AtomTextEdit) -> Self {
        let delete = inner.translate_range(edit.delete);
        let mut res = TranslatedNewlines {
            inner,
            next_inner: None,
            edit: TranslatedAtomEdit {
                delete,
                insert: &edit.insert,
            },
            insert: OffsetNewlineIter {
                offset: delete.start(),
                text: &edit.insert,
            },
        };
        // prepare next_inner
        res.advance_inner();
        res
    }

    fn advance_inner(&mut self) {
        self.next_inner = self
            .inner
            .next_translated()
            .map(|x| translate_offset(x, &self.edit));
    }
}

impl<'a, T: TranslatedNewlineIterator> TranslatedNewlineIterator for TranslatedNewlines<'a, T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        let offset = self.inner.translate(offset);
        let (_, offset) =
            translate_offset(offset, &self.edit).expect("translate_unit returned None");
        offset
    }

    fn next_translated(&mut self) -> Option<TextUnit> {
        match self.next_inner {
            None => self.insert.next(),
            Some(next) => match next {
                None => self.insert.next().or_else(|| {
                    self.advance_inner();
                    self.next_translated()
                }),
                Some((TranslatedPos::Before, next)) => {
                    self.advance_inner();
                    Some(next)
                }
                Some((TranslatedPos::After, next)) => self.insert.next().or_else(|| {
                    self.advance_inner();
                    Some(next)
                }),
            },
        }
    }
}

impl<'a> Iterator for Box<dyn TranslatedNewlineIterator + 'a> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        self.next_translated()
    }
}

impl<T: TranslatedNewlineIterator + ?Sized> TranslatedNewlineIterator for Box<T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        self.as_ref().translate(offset)
    }
    fn next_translated(&mut self) -> Option<TextUnit> {
        self.as_mut().next_translated()
    }
}

struct IteratorWrapper<T: Iterator<Item = TextUnit>>(T);

impl<T: Iterator<Item = TextUnit>> TranslatedNewlineIterator for IteratorWrapper<T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        offset
    }
    fn next_translated(&mut self) -> Option<TextUnit> {
        self.0.next()
    }
}

impl<T: Iterator<Item = TextUnit>> Iterator for IteratorWrapper<T> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        self.0.next()
    }
}

fn translate_newlines<'a>(
    mut newlines: Box<TranslatedNewlineIterator + 'a>,
    edits: &'a [AtomTextEdit],
) -> Box<TranslatedNewlineIterator + 'a> {
    for edit in edits {
        newlines = TranslatedNewlines::from(newlines, edit).boxed();
    }
    newlines
}

pub fn translate_offset_with_edit(
    pre_edit_index: &LineIndex,
    offset: TextUnit,
    edits: &[AtomTextEdit],
) -> LineCol {
    let mut newlines: Box<TranslatedNewlineIterator> = Box::new(IteratorWrapper(
        pre_edit_index.newlines().iter().map(|x| *x),
    ));

    newlines = translate_newlines(newlines, edits);

    let mut line = 0;
    for n in newlines {
        if n > offset {
            break;
        }
        line += 1;
    }

    LineCol {
        line: line,
        col_utf16: 0, // TODO not implemented yet
    }
}

#[cfg(test)]
mod test {
    use proptest::{prelude::*, proptest, proptest_helper};
    use super::*;
    use ra_text_edit::test_utils::{arb_text, arb_offset, arb_edits};

    #[derive(Debug)]
    struct ArbTextWithOffsetAndEdits {
        text: String,
        offset: TextUnit,
        edits: Vec<AtomTextEdit>,
    }

    fn arb_text_with_offset_and_edits() -> BoxedStrategy<ArbTextWithOffsetAndEdits> {
        arb_text()
            .prop_flat_map(|text| {
                (arb_offset(&text), arb_edits(&text), Just(text)).prop_map(
                    |(offset, edits, text)| ArbTextWithOffsetAndEdits {
                        text,
                        offset,
                        edits,
                    },
                )
            })
            .boxed()
    }

    fn edit_text(pre_edit_text: &str, mut edits: Vec<AtomTextEdit>) -> String {
        // apply edits ordered from last to first
        // since they should not overlap we can just use start()
        edits.sort_by_key(|x| -(x.delete.start().to_usize() as isize));

        let mut text = pre_edit_text.to_owned();

        for edit in &edits {
            let range = edit.delete.start().to_usize()..edit.delete.end().to_usize();
            text.replace_range(range, &edit.insert);
        }

        text
    }

    fn translate_after_edit(
        pre_edit_text: &str,
        offset: TextUnit,
        edits: Vec<AtomTextEdit>,
    ) -> LineCol {
        let text = edit_text(pre_edit_text, edits);
        let line_index = LineIndex::new(&text);
        line_index.line_col(offset)
    }

    proptest! {
        #[test]
        fn test_translate_offset_with_edit(x in arb_text_with_offset_and_edits()) {
            let line_index = LineIndex::new(&x.text);
            let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
            let actual = translate_offset_with_edit(&line_index, x.offset, &x.edits);
            assert_eq!(actual.line, expected.line);
        }
    }
}
<commit_msg>simplified version<commit_after>use ra_text_edit::{AtomTextEdit};
use ra_syntax::{TextUnit, TextRange};
use crate::{LineIndex, LineCol};
use superslice::Ext;

#[derive(Debug)]
struct OffsetNewlineIter<'a> {
    text: &'a str,
    offset: TextUnit,
}

impl<'a> Iterator for OffsetNewlineIter<'a> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        let next_idx = self
            .text
            .char_indices()
            .filter_map(|(i, c)| if c == '\n' { Some(i + 1) } else { None })
            .next()?;
        let next = self.offset + TextUnit::from_usize(next_idx);
        self.text = &self.text[next_idx..];
        self.offset = next;
        Some(next)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum TranslatedPos {
    Before,
    After,
}

/// None means it was deleted
type TranslatedOffset = Option<(TranslatedPos, TextUnit)>;

fn translate_offset(offset: TextUnit, edit: &TranslatedAtomEdit) -> TranslatedOffset {
    if offset <= edit.delete.start() {
        Some((TranslatedPos::Before, offset))
    } else if offset <= edit.delete.end() {
        None
    } else {
        let diff = edit.insert.len() as i64 - edit.delete.len().to_usize() as i64;
        let after = TextUnit::from((offset.to_usize() as i64 + diff) as u32);
        Some((TranslatedPos::After, after))
    }
}

trait TranslatedNewlineIterator {
    fn translate(&self, offset: TextUnit) -> TextUnit;
    fn translate_range(&self, range: TextRange) -> TextRange {
        TextRange::from_to(self.translate(range.start()), self.translate(range.end()))
    }
    fn next_translated(&mut self) -> Option<TextUnit>;
    fn boxed<'a>(self) -> Box<TranslatedNewlineIterator + 'a>
    where
        Self: 'a + Sized,
    {
        Box::new(self)
    }
}

#[derive(Debug)]
struct AltEdit<'a> {
    insert_newlines: OffsetNewlineIter<'a>,
    delete: TextRange,
    diff: i64,
}

fn translate_range_by(range: TextRange, diff: i64) -> TextRange {
    if diff == 0 {
        range
    } else {
        let start = translate_by(range.start(), diff);
        let end = translate_by(range.end(), diff);
        TextRange::from_to(start, end)
    }
}

fn translate_by(x: TextUnit, diff: i64) -> TextUnit {
    if diff == 0 {
        x
    } else {
        TextUnit::from((x.to_usize() as i64 + diff) as u32)
    }
}

fn to_alt_edits<'a>(offset: TextUnit, edits: &'a [AtomTextEdit]) -> Vec<AltEdit<'a>> {
    let mut xs: Vec<AltEdit<'a>> = Vec::with_capacity(edits.len());
    // collect and sort edits
    for edit in edits {
        // TODO discard after translating?
        // if edit.delete.start() >= offset {
        //     continue;
        // }
        let insert_index = xs.upper_bound_by_key(&edit.delete.start(), |x| x.delete.start());
        let diff = edit.insert.len() as i64 - edit.delete.len().to_usize() as i64;
        xs.insert(
            insert_index,
            AltEdit {
                insert_newlines: OffsetNewlineIter {
                    offset: edit.delete.start(),
                    text: &edit.insert,
                },
                delete: edit.delete,
                diff: diff,
            },
        );
    }
    // translate edits by previous edits
    for i in 1..xs.len() {
        let (x, prevs) = xs[0..=i].split_last_mut().unwrap();
        for prev in prevs {
            x.delete = translate_range_by(x.delete, prev.diff);
            x.insert_newlines.offset = translate_by(x.insert_newlines.offset, prev.diff);
        }
    }
    xs
}

#[derive(Debug)]
enum NextNewline {
    Use,
    Discard,
    Replace(TextUnit),
    New(TextUnit),
}

fn next_newline(candidate: Option<TextUnit>, edits: &mut [AltEdit]) -> NextNewline {
    let mut candidate = match candidate {
        None => {
            for edit in edits {
                if let Some(inserted) = edit.insert_newlines.next() {
                    return NextNewline::New(inserted);
                }
            }
            return NextNewline::Use; // END
        }
        Some(x) => x,
    };

    for edit in edits {
        if candidate <= edit.delete.start() {
            return NextNewline::Replace(candidate);
        } else if candidate <= edit.delete.end() {
            return match edit.insert_newlines.next() {
                Some(x) => NextNewline::Replace(x),
                None => NextNewline::Discard,
            };
        } else {
            if let Some(inserted) = edit.insert_newlines.next() {
                return NextNewline::New(inserted);
            }
            candidate = translate_by(candidate, edit.diff);
        }
    }
    return NextNewline::Replace(candidate);
}

fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 {
    let mut edits = to_alt_edits(offset, edits);
    let mut orig_newlines = line_index.newlines().iter().map(|x| *x).peekable();

    let mut count = 0;

    loop {
        let res = next_newline(orig_newlines.peek().map(|x| *x), &mut edits);
        let next = match res {
            NextNewline::Use => orig_newlines.next(),
            NextNewline::Discard => {
                orig_newlines.next();
                continue;
            }
            NextNewline::Replace(new) => {
                orig_newlines.next();
                Some(new)
            }
            NextNewline::New(new) => Some(new),
        };
        match next {
            Some(n) if n <= offset => {
                count += 1;
            }
            _ => {
                break;
            }
        }
    }

    count
}

struct TranslatedAtomEdit<'a> {
    delete: TextRange,
    insert: &'a str,
}

struct TranslatedNewlines<'a, T: TranslatedNewlineIterator> {
    inner: T,
    next_inner: Option<TranslatedOffset>,
    edit: TranslatedAtomEdit<'a>,
    insert: OffsetNewlineIter<'a>,
}

impl<'a, T: TranslatedNewlineIterator> TranslatedNewlines<'a, T> {
    fn from(inner: T, edit: &'a AtomTextEdit) -> Self {
        let delete = inner.translate_range(edit.delete);
        let mut res = TranslatedNewlines {
            inner,
            next_inner: None,
            edit: TranslatedAtomEdit {
                delete,
                insert: &edit.insert,
            },
            insert: OffsetNewlineIter {
                offset: delete.start(),
                text: &edit.insert,
            },
        };
        // prepare next_inner
        res.advance_inner();
        res
    }

    fn advance_inner(&mut self) {
        self.next_inner = self
            .inner
            .next_translated()
            .map(|x| translate_offset(x, &self.edit));
    }
}

impl<'a, T: TranslatedNewlineIterator> TranslatedNewlineIterator for TranslatedNewlines<'a, T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        let offset = self.inner.translate(offset);
        let (_, offset) =
            translate_offset(offset, &self.edit).expect("translate_unit returned None");
        offset
    }

    fn next_translated(&mut self) -> Option<TextUnit> {
        match self.next_inner {
            None => self.insert.next(),
            Some(next) => match next {
                None => self.insert.next().or_else(|| {
                    self.advance_inner();
                    self.next_translated()
                }),
                Some((TranslatedPos::Before, next)) => {
                    self.advance_inner();
                    Some(next)
                }
                Some((TranslatedPos::After, next)) => self.insert.next().or_else(|| {
                    self.advance_inner();
                    Some(next)
                }),
            },
        }
    }
}

impl<'a> Iterator for Box<dyn TranslatedNewlineIterator + 'a> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        self.next_translated()
    }
}

impl<T: TranslatedNewlineIterator + ?Sized> TranslatedNewlineIterator for Box<T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        self.as_ref().translate(offset)
    }
    fn next_translated(&mut self) -> Option<TextUnit> {
        self.as_mut().next_translated()
    }
}

struct IteratorWrapper<T: Iterator<Item = TextUnit>>(T);

impl<T: Iterator<Item = TextUnit>> TranslatedNewlineIterator for IteratorWrapper<T> {
    fn translate(&self, offset: TextUnit) -> TextUnit {
        offset
    }
    fn next_translated(&mut self) -> Option<TextUnit> {
        self.0.next()
    }
}

impl<T: Iterator<Item = TextUnit>> Iterator for IteratorWrapper<T> {
    type Item = TextUnit;
    fn next(&mut self) -> Option<TextUnit> {
        self.0.next()
    }
}

fn translate_newlines<'a>(
    mut newlines: Box<TranslatedNewlineIterator + 'a>,
    edits: &'a [AtomTextEdit],
) -> Box<TranslatedNewlineIterator + 'a> {
    for edit in edits {
        newlines = TranslatedNewlines::from(newlines, edit).boxed();
    }
    newlines
}

pub fn translate_offset_with_edit(
    pre_edit_index: &LineIndex,
    offset: TextUnit,
    edits: &[AtomTextEdit],
) -> LineCol {
    let mut newlines: Box<TranslatedNewlineIterator> = Box::new(IteratorWrapper(
        pre_edit_index.newlines().iter().map(|x| *x),
    ));

    newlines = translate_newlines(newlines, edits);

    let mut line = 0;
    for n in newlines {
        if n > offset {
            break;
        }
        line += 1;
    }

    LineCol {
        line: line,
        col_utf16: 0, // TODO not implemented yet
    }
}

#[cfg(test)]
mod test {
    use proptest::{prelude::*, proptest, proptest_helper};
    use super::*;
    use ra_text_edit::test_utils::{arb_text, arb_offset, arb_edits};

    #[derive(Debug)]
    struct ArbTextWithOffsetAndEdits {
        text: String,
        offset: TextUnit,
        edits: Vec<AtomTextEdit>,
    }

    fn arb_text_with_offset_and_edits() -> BoxedStrategy<ArbTextWithOffsetAndEdits> {
        arb_text()
            .prop_flat_map(|text| {
                (arb_offset(&text), arb_edits(&text), Just(text)).prop_map(
                    |(offset, edits, text)| ArbTextWithOffsetAndEdits {
                        text,
                        offset,
                        edits,
                    },
                )
            })
            .boxed()
    }

    fn edit_text(pre_edit_text: &str, mut edits: Vec<AtomTextEdit>) -> String {
        // apply edits ordered from last to first
        // since they should not overlap we can just use start()
        edits.sort_by_key(|x| -(x.delete.start().to_usize() as isize));

        let mut text = pre_edit_text.to_owned();

        for edit in &edits {
            let range = edit.delete.start().to_usize()..edit.delete.end().to_usize();
            text.replace_range(range, &edit.insert);
        }

        text
    }

    fn translate_after_edit(
        pre_edit_text: &str,
        offset: TextUnit,
        edits: Vec<AtomTextEdit>,
    ) -> LineCol {
        let text = edit_text(pre_edit_text, edits);
        let line_index = LineIndex::new(&text);
        line_index.line_col(offset)
    }

    proptest! {
        #[test]
        fn test_translate_offset_with_edit(x in arb_text_with_offset_and_edits()) {
            let line_index = LineIndex::new(&x.text);
            let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
            let actual = translate_offset_with_edit(&line_index, x.offset, &x.edits);
            assert_eq!(actual.line, expected.line);
        }

        #[test]
        fn test_translate_offset_with_edit_alt(x in arb_text_with_offset_and_edits()) {
            let line_index = LineIndex::new(&x.text);
            let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
            let actual_lines = count_newlines(x.offset, &line_index, &x.edits);
            assert_eq!(actual_lines, expected.line);
        }
    }
}
<|endoftext|>


<commit_before>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
#[cfg(any(target_os = "android", target_os = "linux"))]
use nix::sys::ptrace::Options;

#[cfg(any(target_os = "android", target_os = "linux"))]
use std::mem;

use crate::*;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
            err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setoptions() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getevent() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    let siginfo = unsafe { mem::zeroed() };
    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // FIXME: qemu-user doesn't implement ptrace on all architectures
    // and retunrs ENOSYS in this case.
    // We (ab)use this behavior to detect the affected platforms
    // and skip the test then.
    // On valid platforms the ptrace call should return Errno::EPERM, this
    // is already tested by `test_ptrace`.
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match unsafe{fork()}.expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
                    // FIXME It's been observed on some systems (apple) the
                    // tracee may not be killed but remain as a zombie process
                    // affecting other wait based tests. Add an extra kill just
                    // to make sure there are no zombies.
                    let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
                        let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    }
                }
                _ => panic!("The process should have been killed"),
            }
        },
    }
}

// ptrace::{setoptions, getregs} are only available in these platforms
#[cfg(all(target_os = "linux",
          any(target_arch = "x86_64",
              target_arch = "x86"),
          target_env = "gnu"))]
#[test]
fn test_ptrace_syscall() {
    use nix::sys::signal::kill;
    use nix::sys::ptrace;
    use nix::sys::signal::Signal;
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::getpid;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    match unsafe{fork()}.expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // first sigstop until parent is ready to continue
            let pid = getpid();
            kill(pid, Signal::SIGSTOP).unwrap();
            kill(pid, Signal::SIGTERM).unwrap();
            unsafe { ::libc::_exit(0); }
        },

        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));

            // set this option to recognize syscall-stops
            ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();

            #[cfg(target_pointer_width = "64")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;

            #[cfg(target_pointer_width = "32")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32;

            // kill entry
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // kill exit
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // receive signal
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));

            // inject signal
            ptrace::syscall(child, Signal::SIGTERM).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
        },
    }
}
<commit_msg>Fix test_ptrace_syscall() on x32<commit_after>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
#[cfg(any(target_os = "android", target_os = "linux"))]
use nix::sys::ptrace::Options;

#[cfg(any(target_os = "android", target_os = "linux"))]
use std::mem;

use crate::*;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
            err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setoptions() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getevent() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    let siginfo = unsafe { mem::zeroed() };
    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // FIXME: qemu-user doesn't implement ptrace on all architectures
    // and retunrs ENOSYS in this case.
    // We (ab)use this behavior to detect the affected platforms
    // and skip the test then.
    // On valid platforms the ptrace call should return Errno::EPERM, this
    // is already tested by `test_ptrace`.
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match unsafe{fork()}.expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
                    // FIXME It's been observed on some systems (apple) the
                    // tracee may not be killed but remain as a zombie process
                    // affecting other wait based tests. Add an extra kill just
                    // to make sure there are no zombies.
                    let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
                        let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    }
                }
                _ => panic!("The process should have been killed"),
            }
        },
    }
}

// ptrace::{setoptions, getregs} are only available in these platforms
#[cfg(all(target_os = "linux",
          any(target_arch = "x86_64",
              target_arch = "x86"),
          target_env = "gnu"))]
#[test]
fn test_ptrace_syscall() {
    use nix::sys::signal::kill;
    use nix::sys::ptrace;
    use nix::sys::signal::Signal;
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::getpid;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    match unsafe{fork()}.expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // first sigstop until parent is ready to continue
            let pid = getpid();
            kill(pid, Signal::SIGSTOP).unwrap();
            kill(pid, Signal::SIGTERM).unwrap();
            unsafe { ::libc::_exit(0); }
        },

        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));

            // set this option to recognize syscall-stops
            ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();

            #[cfg(target_arch = "x86_64")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;

            #[cfg(target_arch = "x86")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;

            // kill entry
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // kill exit
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // receive signal
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));

            // inject signal
            ptrace::syscall(child, Signal::SIGTERM).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
        },
    }
}
<|endoftext|>


<commit_before>extern crate timely;
extern crate differential_dataflow;
extern crate dd_server;

use std::rc::Rc;
use std::cell::RefCell;

use timely::dataflow::operators::inspect::Inspect;
use timely::dataflow::operators::Probe;
use differential_dataflow::operators::CountTotal;
use dd_server::{Environment, TraceHandle};

// load ./dataflows/degr_dist/target/release/libdegr_dist.dylib build <graph_name>

#[no_mangle]
pub fn build((dataflow, handles, probe, _timer, args): Environment) -> Result<(), String> {

    if args.len() != 1 { return Err(format!("expected one argument, instead: {:?}", args)); }

    let timer = _timer.clone();

    println!("{:?}: degree monitoring started", timer.elapsed());

    let mut delays = vec![0usize; 32];

    handles
        .get_mut::<Rc<RefCell<Option<TraceHandle>>>>(&args[0])?
        .borrow_mut().as_mut().unwrap()
        .import(dataflow)
        .as_collection(|k,v| (k.clone(), v.clone()))
        .map(|(src, _dst)| src as usize).count_total()
        .map(|(_src, cnt)| cnt as usize).count_total()
        // now we capture the observed latency on each record.
        .inner
        .inspect_batch(move |_, data| {

            let mut delays = [0usize; 32];

            let elapsed = timer.elapsed();
            let elapsed_ns = (elapsed.as_secs() as usize) * 1_000_000_000 + (elapsed.subsec_nanos() as usize);
            for &(_, ref time, _) in data.iter() {
                let delay_us = (elapsed_ns - time.inner) / 1000;
                let bin = delay_us.next_power_of_two().trailing_zeros() as usize;
                delays[bin] += 1;
            }
            println!("delays: {:?}", delays);
        })
        .probe_with(probe);

    Ok(())
}<commit_msg>clearer latency reporting<commit_after>extern crate timely;
extern crate differential_dataflow;
extern crate dd_server;

use std::rc::Rc;
use std::cell::RefCell;

use timely::dataflow::operators::{Probe, Operator};
use differential_dataflow::operators::CountTotal;
use dd_server::{Environment, TraceHandle};

// load ./dataflows/degr_dist/target/release/libdegr_dist.dylib build <graph_name>

#[no_mangle]
pub fn build((dataflow, handles, probe, _timer, args): Environment) -> Result<(), String> {

    if args.len() != 1 { return Err(format!("expected one argument, instead: {:?}", args)); }

    let timer = _timer.clone();

    println!("{:?}: degree monitoring started", timer.elapsed());

    let mut delays = vec![0usize; 64];

    handles
        .get_mut::<Rc<RefCell<Option<TraceHandle>>>>(&args[0])?
        .borrow_mut().as_mut().unwrap()
        .import(dataflow)
        .as_collection(|k,v| (k.clone(), v.clone()))
        .map(|(src, _dst)| src as usize).count_total()
        .map(|(_src, cnt)| cnt as usize).count_total()
        // now we capture the observed latency on each record.
        .inner
        .unary(::timely::dataflow::channels::pact::Pipeline, "MeasureLatency", |_cap| {
            move |input, output| {

                let mut delays = [0usize; 64];

                let elapsed = timer.elapsed();
                let elapsed_ns = (elapsed.as_secs() as usize) * 1_000_000_000 + (elapsed.subsec_nanos() as usize);

                input.for_each(|cap, data| {
                    for &(_, ref time, _) in data.iter() {
                        let delay_ns = elapsed_ns - time.inner;
                        let bin = delay_ns.next_power_of_two().trailing_zeros() as usize;
                        delays[bin] += 1;
                    }
                    output.session(&cap).give(());
                });

                println!("delays (samples taking at most):");
                for i in 0 .. 64 {
                    if delays[i] > 0 {
                        println!("\t{}ns:\t{}", 1 << i, delays[i]);
                    }
                }
            }
        })
        .probe_with(probe);

    Ok(())
}<|endoftext|>


<commit_before>//! Core LR(1) types.

use collections::Map;
use grammar::repr::*;
use itertools::Itertools;
use std::fmt::{Debug, Display, Formatter, Error};
use std::rc::Rc;
use util::Prefix;

use super::lookahead::*;

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Item<'grammar, L: Lookahead> {
    pub production: &'grammar Production,
    /// the dot comes before `index`, so `index` would be 1 for X = A (*) B C
    pub index: usize,
    pub lookahead: L,
}

pub type LR0Item<'grammar> = Item<'grammar, Nil>;

pub type LR1Item<'grammar> = Item<'grammar, Token>;

impl<'grammar> Item<'grammar, Nil> {
    #[cfg(test)]
    pub fn lr0(production: &'grammar Production,
               index: usize)
               -> Self {
        Item { production: production, index: index, lookahead: Nil }
    }
}

impl<'grammar, L: Lookahead> Item<'grammar, L> {
    pub fn prefix(&self) -> &'grammar [Symbol] {
        &self.production.symbols[..self.index]
    }

    pub fn symbol_sets(&self) -> SymbolSets<'grammar> {
        let symbols = &self.production.symbols;
        if self.can_shift() {
            SymbolSets {
                prefix: &symbols[..self.index],
                cursor: Some(&symbols[self.index]),
                suffix: &symbols[self.index+1..],
            }
        } else {
            SymbolSets {
                prefix: &symbols[..self.index],
                cursor: None,
                suffix: &[],
            }
        }
    }

    pub fn to_lr0(&self) -> LR0Item<'grammar> {
        Item { production: self.production, index: self.index, lookahead: Nil }
    }

    pub fn can_shift(&self) -> bool {
        self.index < self.production.symbols.len()
    }

    pub fn can_shift_nonterminal(&self, nt: NonterminalString) -> bool {
        match self.shift_symbol() {
            Some((Symbol::Nonterminal(shifted), _)) => shifted == nt,
            _ => false,
        }
    }

    pub fn can_reduce(&self) -> bool {
        self.index == self.production.symbols.len()
    }

    pub fn shifted_item(&self) -> Option<(Symbol, Item<'grammar, L>)> {
        if self.can_shift() {
            Some((self.production.symbols[self.index],
                  Item { production: self.production,
                         index: self.index + 1,
                         lookahead: self.lookahead.clone() }))
        } else {
            None
        }
    }

    pub fn shift_symbol(&self) -> Option<(Symbol, &[Symbol])> {
        if self.can_shift() {
            Some((self.production.symbols[self.index], &self.production.symbols[self.index+1..]))
        } else {
            None
        }
    }
}

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct StateIndex(pub usize);

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Items<'grammar, L: Lookahead> {
    pub vec: Rc<Vec<Item<'grammar, L>>>
}

pub type LR0Items<'grammar> = Items<'grammar, Nil>;
pub type LR1Items<'grammar> = Items<'grammar, Token>;

#[derive(Debug)]
pub struct State<'grammar, L: Lookahead> {
    pub index: StateIndex,
    pub items: Items<'grammar, L>,
    pub shifts: Map<TerminalString, StateIndex>,
    pub reductions: Map<L, &'grammar Production>,
    pub conflicts: Vec<Conflict<'grammar, L>>,
    pub gotos: Map<NonterminalString, StateIndex>,
}

pub type LR0State<'grammar> = State<'grammar, Nil>;
pub type LR1State<'grammar> = State<'grammar, Token>;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Action<'grammar> {
    Shift(TerminalString, StateIndex),
    Reduce(&'grammar Production),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Conflict<'grammar, L: Lookahead> {
    // when in this state...
    pub state: StateIndex,

    // with the following lookahead...
    pub lookahead: L,

    // we can reduce...
    pub production: &'grammar Production,

    // but we can also...
    pub action: Action<'grammar>,
}

pub type LR0Conflict<'grammar> = Conflict<'grammar, Nil>;
pub type LR1Conflict<'grammar> = Conflict<'grammar, Token>;

#[derive(Debug)]
pub struct TableConstructionError<'grammar, L: Lookahead> {
    // LR(1) state set. Some of these states are in error.
    pub states: Vec<State<'grammar, L>>,
}

pub type LR0TableConstructionError<'grammar> = TableConstructionError<'grammar, Nil>;
pub type LR1TableConstructionError<'grammar> = TableConstructionError<'grammar, Token>;

impl<'grammar, L: Lookahead> Debug for Item<'grammar, L> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{} ={} (*){}",
                    self.production.nonterminal,
                    Prefix(" ", &self.production.symbols[..self.index]),
                    Prefix(" ", &self.production.symbols[self.index..])));

        self.lookahead.fmt_as_item_suffix(fmt)
    }
}

impl Display for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Token::EOF => write!(fmt, "EOF"),
            Token::Terminal(s) => write!(fmt, "{}", s),
        }
    }
}

impl Debug for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self)
    }
}

impl Debug for StateIndex {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "S{}", self.0)
    }
}

impl<'grammar, L: Lookahead> State<'grammar, L> {
    /// Returns the set of symbols which must appear on the stack to
    /// be in this state. This is the *maximum* prefix of any item,
    /// basically.
    pub fn max_prefix(&self) -> &'grammar [Symbol] {
        // Each state fn takes as argument the longest prefix of any
        // item. Note that all items must have compatible prefixes.
        let prefix =
            self.items.vec
                      .iter()
                      .map(|item| item.prefix())
                      .max_by_key(|symbols| symbols.len())
                      .unwrap();

        debug_assert!(
            self.items.vec
                      .iter()
                      .all(|item| prefix.ends_with(&item.production.symbols[..item.index])));

        prefix
    }

    /// Returns the set of symbols from the stack that must be popped
    /// for this state to return. If we have a state like:
    ///
    /// ```
    /// X = A B C (*) C
    /// Y = B C (*) C
    /// C = (*) ...
    /// ```
    ///
    /// This would return `[B, C]`. For every state other than the
    /// start state, this will return a list of length at least 1.
    /// For the start state, returns `[]`.
    pub fn will_pop(&self) -> &'grammar [Symbol] {
        let prefix =
            self.items.vec.iter()
                          .filter(|item| item.index > 0)
                          .map(|item| item.prefix())
                          .min_by_key(|symbols| symbols.len())
                          .unwrap_or(&[]);

        debug_assert!(
            self.items.vec
                      .iter()
                      .filter(|item| item.index > 0)
                      .all(|item| item.prefix().ends_with(prefix)));

        prefix
    }

    pub fn will_push(&self) -> &[Symbol] {
        self.items.vec.iter()
                      .filter(|item| item.index > 0)
                      .map(|item| &item.production.symbols[item.index..])
                      .min_by_key(|symbols| symbols.len())
                      .unwrap_or(&[])
    }

    /// Returns the type of nonterminal that this state will produce;
    /// if `None` is returned, then this state may produce more than
    /// one kind of nonterminal.
    ///
    /// FIXME -- currently, the start state returns `None` instead of
    /// the goal symbol.
    pub fn will_produce(&self) -> Option<NonterminalString> {
        let mut returnable_nonterminals: Vec<_> =
            self.items.vec.iter()
                          .filter(|item| item.index > 0)
                          .map(|item| item.production.nonterminal)
                          .dedup()
                          .collect();
        if returnable_nonterminals.len() == 1 {
            returnable_nonterminals.pop()
        } else {
            None
        }
    }

}

/// `A = B C (*) D E F` or `A = B C (*)`
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SymbolSets<'grammar> {
    pub prefix: &'grammar [Symbol], // both cases, [B, C]
    pub cursor: Option<&'grammar Symbol>, // first [D], second []
    pub suffix: &'grammar [Symbol], // first [E, F], second []
}

impl<'grammar> SymbolSets<'grammar> {
    pub fn new() -> Self {
        SymbolSets {
            prefix: &[],
            cursor: None,
            suffix: &[],
        }
    }
}
<commit_msg>add can_shift_terminal helper<commit_after>//! Core LR(1) types.

use collections::Map;
use grammar::repr::*;
use itertools::Itertools;
use std::fmt::{Debug, Display, Formatter, Error};
use std::rc::Rc;
use util::Prefix;

use super::lookahead::*;

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Item<'grammar, L: Lookahead> {
    pub production: &'grammar Production,
    /// the dot comes before `index`, so `index` would be 1 for X = A (*) B C
    pub index: usize,
    pub lookahead: L,
}

pub type LR0Item<'grammar> = Item<'grammar, Nil>;

pub type LR1Item<'grammar> = Item<'grammar, Token>;

impl<'grammar> Item<'grammar, Nil> {
    pub fn lr0(production: &'grammar Production,
               index: usize)
               -> Self {
        Item { production: production, index: index, lookahead: Nil }
    }
}

impl<'grammar, L: Lookahead> Item<'grammar, L> {
    pub fn prefix(&self) -> &'grammar [Symbol] {
        &self.production.symbols[..self.index]
    }

    pub fn symbol_sets(&self) -> SymbolSets<'grammar> {
        let symbols = &self.production.symbols;
        if self.can_shift() {
            SymbolSets {
                prefix: &symbols[..self.index],
                cursor: Some(&symbols[self.index]),
                suffix: &symbols[self.index+1..],
            }
        } else {
            SymbolSets {
                prefix: &symbols[..self.index],
                cursor: None,
                suffix: &[],
            }
        }
    }

    pub fn to_lr0(&self) -> LR0Item<'grammar> {
        Item { production: self.production, index: self.index, lookahead: Nil }
    }

    pub fn can_shift(&self) -> bool {
        self.index < self.production.symbols.len()
    }

    pub fn can_shift_nonterminal(&self, nt: NonterminalString) -> bool {
        match self.shift_symbol() {
            Some((Symbol::Nonterminal(shifted), _)) => shifted == nt,
            _ => false,
        }
    }

    pub fn can_shift_terminal(&self, term: TerminalString) -> bool {
        match self.shift_symbol() {
            Some((Symbol::Terminal(shifted), _)) => shifted == term,
            _ => false,
        }
    }

    pub fn can_reduce(&self) -> bool {
        self.index == self.production.symbols.len()
    }

    pub fn shifted_item(&self) -> Option<(Symbol, Item<'grammar, L>)> {
        if self.can_shift() {
            Some((self.production.symbols[self.index],
                  Item { production: self.production,
                         index: self.index + 1,
                         lookahead: self.lookahead.clone() }))
        } else {
            None
        }
    }

    pub fn shift_symbol(&self) -> Option<(Symbol, &[Symbol])> {
        if self.can_shift() {
            Some((self.production.symbols[self.index], &self.production.symbols[self.index+1..]))
        } else {
            None
        }
    }
}

#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct StateIndex(pub usize);

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Items<'grammar, L: Lookahead> {
    pub vec: Rc<Vec<Item<'grammar, L>>>
}

pub type LR0Items<'grammar> = Items<'grammar, Nil>;
pub type LR1Items<'grammar> = Items<'grammar, Token>;

#[derive(Debug)]
pub struct State<'grammar, L: Lookahead> {
    pub index: StateIndex,
    pub items: Items<'grammar, L>,
    pub shifts: Map<TerminalString, StateIndex>,
    pub reductions: Map<L, &'grammar Production>,
    pub conflicts: Vec<Conflict<'grammar, L>>,
    pub gotos: Map<NonterminalString, StateIndex>,
}

pub type LR0State<'grammar> = State<'grammar, Nil>;
pub type LR1State<'grammar> = State<'grammar, Token>;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Action<'grammar> {
    Shift(TerminalString, StateIndex),
    Reduce(&'grammar Production),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Conflict<'grammar, L: Lookahead> {
    // when in this state...
    pub state: StateIndex,

    // with the following lookahead...
    pub lookahead: L,

    // we can reduce...
    pub production: &'grammar Production,

    // but we can also...
    pub action: Action<'grammar>,
}

pub type LR0Conflict<'grammar> = Conflict<'grammar, Nil>;
pub type LR1Conflict<'grammar> = Conflict<'grammar, Token>;

#[derive(Debug)]
pub struct TableConstructionError<'grammar, L: Lookahead> {
    // LR(1) state set. Some of these states are in error.
    pub states: Vec<State<'grammar, L>>,
}

pub type LR0TableConstructionError<'grammar> = TableConstructionError<'grammar, Nil>;
pub type LR1TableConstructionError<'grammar> = TableConstructionError<'grammar, Token>;

impl<'grammar, L: Lookahead> Debug for Item<'grammar, L> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{} ={} (*){}",
                    self.production.nonterminal,
                    Prefix(" ", &self.production.symbols[..self.index]),
                    Prefix(" ", &self.production.symbols[self.index..])));

        self.lookahead.fmt_as_item_suffix(fmt)
    }
}

impl Display for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Token::EOF => write!(fmt, "EOF"),
            Token::Terminal(s) => write!(fmt, "{}", s),
        }
    }
}

impl Debug for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self)
    }
}

impl Debug for StateIndex {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "S{}", self.0)
    }
}

impl<'grammar, L: Lookahead> State<'grammar, L> {
    /// Returns the set of symbols which must appear on the stack to
    /// be in this state. This is the *maximum* prefix of any item,
    /// basically.
    pub fn max_prefix(&self) -> &'grammar [Symbol] {
        // Each state fn takes as argument the longest prefix of any
        // item. Note that all items must have compatible prefixes.
        let prefix =
            self.items.vec
                      .iter()
                      .map(|item| item.prefix())
                      .max_by_key(|symbols| symbols.len())
                      .unwrap();

        debug_assert!(
            self.items.vec
                      .iter()
                      .all(|item| prefix.ends_with(&item.production.symbols[..item.index])));

        prefix
    }

    /// Returns the set of symbols from the stack that must be popped
    /// for this state to return. If we have a state like:
    ///
    /// ```
    /// X = A B C (*) C
    /// Y = B C (*) C
    /// C = (*) ...
    /// ```
    ///
    /// This would return `[B, C]`. For every state other than the
    /// start state, this will return a list of length at least 1.
    /// For the start state, returns `[]`.
    pub fn will_pop(&self) -> &'grammar [Symbol] {
        let prefix =
            self.items.vec.iter()
                          .filter(|item| item.index > 0)
                          .map(|item| item.prefix())
                          .min_by_key(|symbols| symbols.len())
                          .unwrap_or(&[]);

        debug_assert!(
            self.items.vec
                      .iter()
                      .filter(|item| item.index > 0)
                      .all(|item| item.prefix().ends_with(prefix)));

        prefix
    }

    pub fn will_push(&self) -> &[Symbol] {
        self.items.vec.iter()
                      .filter(|item| item.index > 0)
                      .map(|item| &item.production.symbols[item.index..])
                      .min_by_key(|symbols| symbols.len())
                      .unwrap_or(&[])
    }

    /// Returns the type of nonterminal that this state will produce;
    /// if `None` is returned, then this state may produce more than
    /// one kind of nonterminal.
    ///
    /// FIXME -- currently, the start state returns `None` instead of
    /// the goal symbol.
    pub fn will_produce(&self) -> Option<NonterminalString> {
        let mut returnable_nonterminals: Vec<_> =
            self.items.vec.iter()
                          .filter(|item| item.index > 0)
                          .map(|item| item.production.nonterminal)
                          .dedup()
                          .collect();
        if returnable_nonterminals.len() == 1 {
            returnable_nonterminals.pop()
        } else {
            None
        }
    }

}

/// `A = B C (*) D E F` or `A = B C (*)`
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SymbolSets<'grammar> {
    pub prefix: &'grammar [Symbol], // both cases, [B, C]
    pub cursor: Option<&'grammar Symbol>, // first [D], second []
    pub suffix: &'grammar [Symbol], // first [E, F], second []
}

impl<'grammar> SymbolSets<'grammar> {
    pub fn new() -> Self {
        SymbolSets {
            prefix: &[],
            cursor: None,
            suffix: &[],
        }
    }
}
<|endoftext|>


<commit_before>use hb;
use std::os::raw::c_void;

use std;
use std::marker::PhantomData;

use std::fmt;
use std::fs;
use std::path::Path;
use std::ptr::NonNull;

use common::{HarfbuzzObject, Owned, Shared};

/// A `Blob` manages raw data like e.g. file contents. It refers to a slice of
/// bytes that can be either owned by the `Blob` or not.
///
/// Since it is a simple wrapper for `hb_blob_t` it can be used to construct
/// `Font`s and `Face`s directly from memory.
///
/// To enable shared usage of its data it uses a reference counting mechanism
/// making the `clone` operation very cheap as no data is cloned.
///
/// A `Blob` implements `Into` for every type that satisfies the `AsRef<[u8]>'
/// trait such as `Vec<u8>` and `Box<[u8]>` so owned blobs can be created easily
/// from standard Rust objects.
#[repr(C)]
pub struct Blob<'a> {
    raw: NonNull<hb::hb_blob_t>,
    marker: PhantomData<&'a [u8]>,
}
impl<'a> Blob<'a> {
    /// Create a new `Blob` from the slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes(bytes: &'a [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_READONLY,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a new `Blob` from the mutable slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes_mut(bytes: &'a mut [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a `Blob` from the contents of the file at `path` whose contents
    /// will be read into memory.
    ///
    /// The result will be either a `Blob` that owns the file's contents or an
    /// error that happened while trying to read the file.
    ///
    /// This can be a performance problem if the file is very big. If this turns
    /// out to be a problem consider `mmap`ing the file or splitting it into
    /// smaller chunks before creating a `Blob`.
    pub fn from_file<P: AsRef<Path>>(path: P) -> std::io::Result<Shared<Blob<'static>>> {
        let vec = fs::read(path)?;
        Ok(vec.into())
    }

    /// Create a new mutable `Blob` from a slice of bytes.
    pub fn with_mut_bytes(bytes: &mut [u8]) -> Owned<Blob> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Get a slice of the `Blob`'s bytes.
    pub fn get_data(&self) -> &[u8] {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data(self.as_raw(), &mut length as *mut _);
            std::slice::from_raw_parts(data_ptr as *const u8, length as usize)
        }
    }

    /// Creates an immutable `Blob` that contains part of the data of the parent
    /// `Blob`. The parent `Blob` will be immutable after this and the sub`Blob`
    /// cannot outlive its parent.
    ///
    /// ### Arguments
    /// * `offset`: Byte-offset of sub-blob within parent.
    /// * `length`: Length of the sub-blob.
    pub fn create_sub_blob(&self, offset: usize, length: usize) -> Shared<Blob<'a>> {
        let blob =
            unsafe { hb::hb_blob_create_sub_blob(self.as_raw(), offset as u32, length as u32) };
        unsafe { Shared::from_raw_owned(blob) }
    }

    /// Returns true if the blob is immutable.
    pub fn is_immutable(&self) -> bool {
        unsafe { hb::hb_blob_is_immutable(self.as_raw()) == 1 }
    }

    /// Makes this blob immutable so the bytes it refers to will never change
    /// during its lifetime.
    pub fn make_immutable(&mut self) {
        unsafe { hb::hb_blob_make_immutable(self.as_raw()) }
    }

    /// Try to get a mutable slice of the `Blob`'s bytes, possibly copying them.
    ///
    /// This returns `None` if the blob is immutable or memory allocation
    /// failed.
    pub fn try_get_mut_data(&mut self) -> Option<&'a mut [u8]> {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data_writable(self.as_raw(), &mut length as *mut _);
            if data_ptr.is_null() {
                None
            } else {
                Some(std::slice::from_raw_parts_mut(
                    data_ptr as *mut u8,
                    length as usize,
                ))
            }
        }
    }
}

impl<'a> fmt::Debug for Blob<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Blob")
            .field("data", &self.get_data())
            .finish()
    }
}

unsafe impl<'a> HarfbuzzObject for Blob<'a> {
    type Raw = hb::hb_blob_t;

    unsafe fn from_raw(raw: *const hb::hb_blob_t) -> Self {
        Blob {
            raw: NonNull::new_unchecked(raw as *mut _),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_blob_t {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_blob_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_blob_destroy(self.as_raw());
    }
}

use std::ops::Deref;
impl<'a> Deref for Blob<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::AsRef;
impl<'a> AsRef<[u8]> for Blob<'a> {
    fn as_ref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::From;

impl<'a, T> From<T> for Shared<Blob<'a>>
where
    T: 'a + Send + AsRef<[u8]>,
{
    fn from(container: T) -> Shared<Blob<'a>> {
        let len = container.as_ref().len();
        let ptr = container.as_ref().as_ptr();

        let data = Box::into_raw(Box::new(container));

        extern "C" fn destroy<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }

        let hb_blob = unsafe {
            hb::hb_blob_create(
                ptr as *const i8,
                len as u32,
                hb::HB_MEMORY_MODE_READONLY,
                data as *mut _,
                Some(destroy::<T>),
            )
        };
        unsafe { Shared::from_raw_owned(hb_blob) }
    }
}

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

    #[test]
    fn test_vec_to_blob_conversion() {
        let a_vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
        let blob: Shared<Blob> = a_vec.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }

    use std::sync::Arc;
    #[test]
    fn test_arc_to_blob_conversion() {
        let rc_slice: Arc<[u8]> = Arc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
        let blob: Shared<Blob<'static>> = rc_slice.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }
}
<commit_msg>Remove redundant method of `Blob`<commit_after>use hb;
use std::os::raw::c_void;

use std;
use std::marker::PhantomData;

use std::fmt;
use std::fs;
use std::path::Path;
use std::ptr::NonNull;

use common::{HarfbuzzObject, Owned, Shared};

/// A `Blob` manages raw data like e.g. file contents. It refers to a slice of
/// bytes that can be either owned by the `Blob` or not.
///
/// Since it is a simple wrapper for `hb_blob_t` it can be used to construct
/// `Font`s and `Face`s directly from memory.
///
/// To enable shared usage of its data it uses a reference counting mechanism
/// making the `clone` operation very cheap as no data is cloned.
///
/// A `Blob` implements `Into` for every type that satisfies the `AsRef<[u8]>'
/// trait such as `Vec<u8>` and `Box<[u8]>` so owned blobs can be created easily
/// from standard Rust objects.
#[repr(C)]
pub struct Blob<'a> {
    raw: NonNull<hb::hb_blob_t>,
    marker: PhantomData<&'a [u8]>,
}
impl<'a> Blob<'a> {
    /// Create a new `Blob` from the slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes(bytes: &'a [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_READONLY,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a new `Blob` from the mutable slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes_mut(bytes: &'a mut [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a `Blob` from the contents of the file at `path` whose contents
    /// will be read into memory.
    ///
    /// The result will be either a `Blob` that owns the file's contents or an
    /// error that happened while trying to read the file.
    ///
    /// This can be a performance problem if the file is very big. If this turns
    /// out to be a problem consider `mmap`ing the file or splitting it into
    /// smaller chunks before creating a `Blob`.
    pub fn from_file<P: AsRef<Path>>(path: P) -> std::io::Result<Shared<Blob<'static>>> {
        let vec = fs::read(path)?;
        Ok(vec.into())
    }

    /// Get a slice of the `Blob`'s bytes.
    pub fn get_data(&self) -> &[u8] {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data(self.as_raw(), &mut length as *mut _);
            std::slice::from_raw_parts(data_ptr as *const u8, length as usize)
        }
    }

    /// Creates an immutable `Blob` that contains part of the data of the parent
    /// `Blob`. The parent `Blob` will be immutable after this and the sub`Blob`
    /// cannot outlive its parent.
    ///
    /// ### Arguments
    /// * `offset`: Byte-offset of sub-blob within parent.
    /// * `length`: Length of the sub-blob.
    pub fn create_sub_blob(&self, offset: usize, length: usize) -> Shared<Blob<'a>> {
        let blob =
            unsafe { hb::hb_blob_create_sub_blob(self.as_raw(), offset as u32, length as u32) };
        unsafe { Shared::from_raw_owned(blob) }
    }

    /// Returns true if the blob is immutable.
    pub fn is_immutable(&self) -> bool {
        unsafe { hb::hb_blob_is_immutable(self.as_raw()) == 1 }
    }

    /// Makes this blob immutable so the bytes it refers to will never change
    /// during its lifetime.
    pub fn make_immutable(&mut self) {
        unsafe { hb::hb_blob_make_immutable(self.as_raw()) }
    }

    /// Try to get a mutable slice of the `Blob`'s bytes, possibly copying them.
    ///
    /// This returns `None` if the blob is immutable or memory allocation
    /// failed.
    pub fn try_get_mut_data(&mut self) -> Option<&'a mut [u8]> {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data_writable(self.as_raw(), &mut length as *mut _);
            if data_ptr.is_null() {
                None
            } else {
                Some(std::slice::from_raw_parts_mut(
                    data_ptr as *mut u8,
                    length as usize,
                ))
            }
        }
    }
}

impl<'a> fmt::Debug for Blob<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Blob")
            .field("data", &self.get_data())
            .finish()
    }
}

unsafe impl<'a> HarfbuzzObject for Blob<'a> {
    type Raw = hb::hb_blob_t;

    unsafe fn from_raw(raw: *const hb::hb_blob_t) -> Self {
        Blob {
            raw: NonNull::new_unchecked(raw as *mut _),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_blob_t {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_blob_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_blob_destroy(self.as_raw());
    }
}

use std::ops::Deref;
impl<'a> Deref for Blob<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::AsRef;
impl<'a> AsRef<[u8]> for Blob<'a> {
    fn as_ref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::From;

impl<'a, T> From<T> for Shared<Blob<'a>>
where
    T: 'a + Send + AsRef<[u8]>,
{
    fn from(container: T) -> Shared<Blob<'a>> {
        let len = container.as_ref().len();
        let ptr = container.as_ref().as_ptr();

        let data = Box::into_raw(Box::new(container));

        extern "C" fn destroy<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }

        let hb_blob = unsafe {
            hb::hb_blob_create(
                ptr as *const i8,
                len as u32,
                hb::HB_MEMORY_MODE_READONLY,
                data as *mut _,
                Some(destroy::<T>),
            )
        };
        unsafe { Shared::from_raw_owned(hb_blob) }
    }
}

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

    #[test]
    fn test_vec_to_blob_conversion() {
        let a_vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
        let blob: Shared<Blob> = a_vec.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }

    use std::sync::Arc;
    #[test]
    fn test_arc_to_blob_conversion() {
        let rc_slice: Arc<[u8]> = Arc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
        let blob: Shared<Blob<'static>> = rc_slice.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }
}
<|endoftext|>


<commit_before>//! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api.
mod cancellation;
mod input;

use std::{panic, sync::Arc};

use ra_syntax::{TextUnit, TextRange, SourceFile, TreeArc};
use relative_path::RelativePathBuf;

pub use ::salsa as salsa;
pub use crate::{
    cancellation::Canceled,
    input::{
        FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, Edition,
    },
};

pub trait CheckCanceled: panic::RefUnwindSafe {
    /// Aborts current query if there are pending changes.
    ///
    /// rust-analyzer needs to be able to answer semantic questions about the
    /// code while the code is being modified. A common problem is that a
    /// long-running query is being calculated when a new change arrives.
    ///
    /// We can't just apply the change immediately: this will cause the pending
    /// query to see inconsistent state (it will observe an absence of
    /// repeatable read). So what we do is we **cancel** all pending queries
    /// before applying the change.
    ///
    /// We implement cancellation by panicking with a special value and catching
    /// it on the API boundary. Salsa explicitly supports this use-case.
    fn check_canceled(&self);

    fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled>
    where
        Self: Sized,
        F: FnOnce(&Self) -> T + panic::UnwindSafe,
    {
        panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
            Ok(canceled) => *canceled,
            Err(payload) => panic::resume_unwind(payload),
        })
    }
}

impl<T: salsa::Database + panic::RefUnwindSafe> CheckCanceled for T {
    fn check_canceled(&self) {
        if self.salsa_runtime().is_current_revision_canceled() {
            Canceled::throw()
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FilePosition {
    pub file_id: FileId,
    pub offset: TextUnit,
}

#[derive(Clone, Copy, Debug)]
pub struct FileRange {
    pub file_id: FileId,
    pub range: TextRange,
}

/// Database which stores all significant input facts: source code and project
/// model. Everything else in rust-analyzer is derived from these queries.
#[salsa::query_group(SourceDatabaseStorage)]
pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
    /// Text of the file.
    #[salsa::input]
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    // Parses the file into the syntax tree.
    fn parse(&self, file_id: FileId) -> TreeArc<SourceFile>;
    /// Path to a file, relative to the root of its source root.
    #[salsa::input]
    fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
    /// Source root of the file.
    #[salsa::input]
    fn file_source_root(&self, file_id: FileId) -> SourceRootId;
    /// Contents of the source root.
    #[salsa::input]
    fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
    fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
    /// The crate graph.
    #[salsa::input]
    fn crate_graph(&self) -> Arc<CrateGraph>;
}

fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
    let root = db.source_root(id);
    let graph = db.crate_graph();
    let res =
        root.files.values().filter_map(|&it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
    Arc::new(res)
}

fn parse(db: &impl SourceDatabase, file_id: FileId) -> TreeArc<SourceFile> {
    let text = db.file_text(file_id);
    SourceFile::parse(&*text)
}
<commit_msg>Assert that DB is unwind-safe, instead of proving<commit_after>//! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api.
mod cancellation;
mod input;

use std::{panic, sync::Arc};

use ra_syntax::{TextUnit, TextRange, SourceFile, TreeArc};
use relative_path::RelativePathBuf;

pub use ::salsa as salsa;
pub use crate::{
    cancellation::Canceled,
    input::{
        FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, Edition,
    },
};

pub trait CheckCanceled {
    /// Aborts current query if there are pending changes.
    ///
    /// rust-analyzer needs to be able to answer semantic questions about the
    /// code while the code is being modified. A common problem is that a
    /// long-running query is being calculated when a new change arrives.
    ///
    /// We can't just apply the change immediately: this will cause the pending
    /// query to see inconsistent state (it will observe an absence of
    /// repeatable read). So what we do is we **cancel** all pending queries
    /// before applying the change.
    ///
    /// We implement cancellation by panicking with a special value and catching
    /// it on the API boundary. Salsa explicitly supports this use-case.
    fn check_canceled(&self);

    fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled>
    where
        Self: Sized,
        F: FnOnce(&Self) -> T + panic::UnwindSafe,
    {
        let this = panic::AssertUnwindSafe(self);
        panic::catch_unwind(|| f(*this)).map_err(|err| match err.downcast::<Canceled>() {
            Ok(canceled) => *canceled,
            Err(payload) => panic::resume_unwind(payload),
        })
    }
}

impl<T: salsa::Database> CheckCanceled for T {
    fn check_canceled(&self) {
        if self.salsa_runtime().is_current_revision_canceled() {
            Canceled::throw()
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FilePosition {
    pub file_id: FileId,
    pub offset: TextUnit,
}

#[derive(Clone, Copy, Debug)]
pub struct FileRange {
    pub file_id: FileId,
    pub range: TextRange,
}

/// Database which stores all significant input facts: source code and project
/// model. Everything else in rust-analyzer is derived from these queries.
#[salsa::query_group(SourceDatabaseStorage)]
pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
    /// Text of the file.
    #[salsa::input]
    fn file_text(&self, file_id: FileId) -> Arc<String>;
    // Parses the file into the syntax tree.
    fn parse(&self, file_id: FileId) -> TreeArc<SourceFile>;
    /// Path to a file, relative to the root of its source root.
    #[salsa::input]
    fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
    /// Source root of the file.
    #[salsa::input]
    fn file_source_root(&self, file_id: FileId) -> SourceRootId;
    /// Contents of the source root.
    #[salsa::input]
    fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
    fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
    /// The crate graph.
    #[salsa::input]
    fn crate_graph(&self) -> Arc<CrateGraph>;
}

fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
    let root = db.source_root(id);
    let graph = db.crate_graph();
    let res =
        root.files.values().filter_map(|&it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
    Arc::new(res)
}

fn parse(db: &impl SourceDatabase, file_id: FileId) -> TreeArc<SourceFile> {
    let text = db.file_text(file_id);
    SourceFile::parse(&*text)
}
<|endoftext|>


<commit_before>pub fn _collections() {
    println!("*** Collections ***");

    iterators();
    entries();

    binary_heap();

    println!("");
}

fn iterators() {
    let mut vec = vec![1, 2, 3, 4];

    for x in vec.iter() {
        print!("{} ", x);
    }
    println!("");

    for x in vec.iter_mut() {
        *x += 1;
        print!("{} ", x);
    }
    println!("");

    let vec2 = vec![10, 20, 30, 40];
    vec.extend(vec2);

    use std::collections::VecDeque;
    let buf: VecDeque<_> = vec.into_iter().collect();
}

fn entries() {
    use std::collections::btree_map::BTreeMap;

    let mut count = BTreeMap::new();
    let message = "sea shells by the shore";

    for c in message.chars() {
        *count.entry(c).or_insert(0) += 1;
    }

    assert_eq!(Some(&4), count.get(&'s'));

    for (ch, count) in &count {
        print!("{}: {}, ", ch, count);
    }
    println!("");
}

fn binary_heap() {
    // BinaryHeap struct
    {
        use std::collections::BinaryHeap;

        let mut heap = BinaryHeap::new();

        // nothing there yet
        assert_eq!(None, heap.peek());

        // pushing onto the heap
        heap.push(1);
        heap.push(5);
        heap.push(2);

        // peek what's "on top"
        assert_eq!(Some(&5), heap.peek());

        // number of items in the heap
        assert_eq!(3, heap.len());

        // in "random" order
        for x in &heap {
            print!("{} ", x);
        }
        println!("");

        // popping is in correct order
        assert_eq!(Some(5), heap.pop());
        assert_eq!(Some(2), heap.pop());
        assert_eq!(Some(1), heap.pop());
        assert_eq!(None, heap.pop());

        // clear anything that remains
        heap.clear();

        // not heap is empty
        assert!(heap.is_empty());

        // creating with preallocated capacity
        let mut heap = BinaryHeap::with_capacity(10);
        assert!(heap.capacity() >= 10);
        heap.push(4);

        *heap.peek_mut().unwrap() += 1;
        assert_eq!(Some(&5), heap.peek());

        heap.reserve_exact(8);
        heap.reserve(8);
        heap.shrink_to_fit();

        heap.push(3);
        heap.push(7);
        heap.push(4);

        // println!("Heap into vec: {:?}", heap.into_vec());
        println!("Heap into sorted vec: {:?}", heap.into_sorted_vec());

        let mut heap = BinaryHeap::new();
        heap.push(3);
        heap.push(7);
        heap.push(4);

        for x in heap.drain() {
            print!("{} ", x);
        }
        println!("");

        assert!(heap.is_empty());

        let v = vec![-4, 8, 3, 6, -3];
        let mut a = BinaryHeap::from(v);

        let v = vec![-20, 5, 43];
        let mut b = BinaryHeap::from(v);

        a.append(&mut b);

        println!("{:?}", a.into_sorted_vec());

        assert!(b.is_empty());
    }
}
<commit_msg>[Rust] STD Library - Modules - collections - btree_map<commit_after>pub fn _collections() {
    println!("*** Collections ***");

    iterators();
    entries();

    binary_heap();
    btree_map();

    println!("");
}

fn iterators() {
    let mut vec = vec![1, 2, 3, 4];

    for x in vec.iter() {
        print!("{} ", x);
    }
    println!("");

    for x in vec.iter_mut() {
        *x += 1;
        print!("{} ", x);
    }
    println!("");

    let vec2 = vec![10, 20, 30, 40];
    vec.extend(vec2);

    use std::collections::VecDeque;
    let buf: VecDeque<_> = vec.into_iter().collect();
}

fn entries() {
    use std::collections::btree_map::BTreeMap;

    let mut count = BTreeMap::new();
    let message = "sea shells by the shore";

    for c in message.chars() {
        *count.entry(c).or_insert(0) += 1;
    }

    assert_eq!(Some(&4), count.get(&'s'));

    for (ch, count) in &count {
        print!("{}: {}, ", ch, count);
    }
    println!("");
}

fn binary_heap() {
    // BinaryHeap struct
    {
        use std::collections::BinaryHeap;

        let mut heap = BinaryHeap::new();

        // nothing there yet
        assert_eq!(None, heap.peek());

        // pushing onto the heap
        heap.push(1);
        heap.push(5);
        heap.push(2);

        // peek what's "on top"
        assert_eq!(Some(&5), heap.peek());

        // number of items in the heap
        assert_eq!(3, heap.len());

        // in "random" order
        for x in &heap {
            print!("{} ", x);
        }
        println!("");

        // popping is in correct order
        assert_eq!(Some(5), heap.pop());
        assert_eq!(Some(2), heap.pop());
        assert_eq!(Some(1), heap.pop());
        assert_eq!(None, heap.pop());

        // clear anything that remains
        heap.clear();

        // not heap is empty
        assert!(heap.is_empty());

        // creating with preallocated capacity
        let mut heap = BinaryHeap::with_capacity(10);
        assert!(heap.capacity() >= 10);
        heap.push(4);

        *heap.peek_mut().unwrap() += 1;
        assert_eq!(Some(&5), heap.peek());

        heap.reserve_exact(8);
        heap.reserve(8);
        heap.shrink_to_fit();

        heap.push(3);
        heap.push(7);
        heap.push(4);

        // println!("Heap into vec: {:?}", heap.into_vec());
        println!("Heap into sorted vec: {:?}", heap.into_sorted_vec());

        let mut heap = BinaryHeap::new();
        heap.push(3);
        heap.push(7);
        heap.push(4);

        for x in heap.drain() {
            print!("{} ", x);
        }
        println!("");

        assert!(heap.is_empty());

        let v = vec![-4, 8, 3, 6, -3];
        let mut a = BinaryHeap::from(v);

        let v = vec![-20, 5, 43];
        let mut b = BinaryHeap::from(v);

        a.append(&mut b);

        println!("{:?}", a.into_sorted_vec());

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

fn btree_map() {
    // general example
    {
        use std::collections::BTreeMap;

        let mut movie_reviews = BTreeMap::new();

        // review some movies
        movie_reviews.insert("Pulp Fiction", "Masterpiece");
        movie_reviews.insert("The Godfather", "Very enjoyable");
        movie_reviews.insert("The Blues Brothers", "Eye lyked it alot");

        // check for a specific one
        if !movie_reviews.contains_key("Les Misérables") {
            println!("We've got {} reviews, but Les Misérables ain't one.",
                     movie_reviews.len());
        }

        // this one has spelling mistakes
        movie_reviews.remove("The Blues Brothers");

        // look up the values associated with some keys
        let to_find = ["Up!", "The Godfather"];

        for book in &to_find {
            match movie_reviews.get(book) {
                Some(review) => println!("{}: {}", book, review),
                None => println!("{} is unreviewed.", book),
            }
        }

        // iterate over everything
        for (movie, review) in &movie_reviews {
            println!("{}: \"{}\"", movie, review);

        }
    }

    // entry api
    {
        use std::collections::BTreeMap;

        let mut player_stats = BTreeMap::new();

        fn random_stat_buff() -> u8 {
            42
        }

        // insert a key only if it doesn't exist
        player_stats.entry("health").or_insert(100);

        // same, just using a function
        player_stats.entry("defence").or_insert_with(random_stat_buff);

        // update a key guarding against it possibly not being set
        let stat = player_stats.entry("attack").or_insert(100);
        *stat += random_stat_buff();
    }

    // methods on a BTreeMap
    {
        use std::collections::BTreeMap;

        let mut map = BTreeMap::new();

        map.insert(1, "a");

        if let Some(x) = map.get_mut(&1) {
            *x = "b";
        }

        assert_eq!(map.entry(1).key(), &1);

        map.clear();
        assert!(map.is_empty());

        // methods on entry struct

    }

}
<|endoftext|>