<commit_before>use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::{InlineSiteSymbol, SymbolIter};
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.truncate(self.symbols_size)?;
        buf.parse_u32()?;
        Ok(SymbolIter::new(buf))
    }

    /// Get an iterator over symbols starting at the given index.
    pub fn symbols_at(&self, index: SymbolIndex) -> Result<SymbolIter<'_>> {
        let mut iter = self.symbols()?;
        iter.seek(index);
        Ok(iter)
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

impl Default for LineInfoKind {
    fn default() -> Self {
        LineInfoKind::Statement
    }
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug, PartialEq)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// The optional length of the code.
    pub length: Option<u32>,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u32>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u32>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all file records of this module.
    pub fn files(&self) -> FileIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => FileIterator {
                inner: FileIteratorInner::C13(inner.files()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Returns an iterator over all inlinees in this module.
    pub fn inlinees(&self) -> InlineeIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => InlineeIterator(inner.inlinees()),
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

#[derive(Clone, Debug)]
enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug)]
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl Default for LineIterator<'_> {
    fn default() -> Self {
        LineIterator {
            inner: LineIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}

/// An inlined function that can evaluate to line information.
pub struct Inlinee<'a>(c13::C13Inlinee<'a>);

impl<'a> Inlinee<'a> {
    /// The index of this inlinee in the `IdInformation` stream (IPI).
    pub fn index(&self) -> IdIndex {
        self.0.index()
    }

    /// Returns an iterator over line records for an inline site.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(
        &self,
        parent_offset: PdbInternalSectionOffset,
        inline_site: &InlineSiteSymbol<'a>,
    ) -> InlineeLineIterator<'a> {
        InlineeLineIterator(self.0.lines(parent_offset, inline_site))
    }
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug, Default)]
pub struct InlineeIterator<'a>(c13::C13InlineeIterator<'a>);

impl<'a> FallibleIterator for InlineeIterator<'a> {
    type Item = Inlinee<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        self.0.next().map(|opt| opt.map(Inlinee))
    }
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug, Default)]
pub struct InlineeLineIterator<'a>(c13::C13InlineeLineIterator<'a>);

impl<'a> FallibleIterator for InlineeLineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        self.0.next()
    }
}

#[derive(Clone, Debug)]
enum FileIteratorInner<'a> {
    C13(c13::C13FileIterator<'a>),
}

/// An iterator over file records in a module.
#[derive(Clone, Debug)]
pub struct FileIterator<'a> {
    inner: FileIteratorInner<'a>,
}

impl Default for FileIterator<'_> {
    fn default() -> Self {
        FileIterator {
            inner: FileIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for FileIterator<'a> {
    type Item = FileInfo<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            FileIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<commit_msg>Add missing debug impl for Inlinees<commit_after>use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::{InlineSiteSymbol, SymbolIter};
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.truncate(self.symbols_size)?;
        buf.parse_u32()?;
        Ok(SymbolIter::new(buf))
    }

    /// Get an iterator over symbols starting at the given index.
    pub fn symbols_at(&self, index: SymbolIndex) -> Result<SymbolIter<'_>> {
        let mut iter = self.symbols()?;
        iter.seek(index);
        Ok(iter)
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

impl Default for LineInfoKind {
    fn default() -> Self {
        LineInfoKind::Statement
    }
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug, PartialEq)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// The optional length of the code.
    pub length: Option<u32>,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u32>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u32>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all file records of this module.
    pub fn files(&self) -> FileIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => FileIterator {
                inner: FileIteratorInner::C13(inner.files()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Returns an iterator over all inlinees in this module.
    pub fn inlinees(&self) -> InlineeIterator<'a> {
        match self.inner {
            LineProgramInner::C13(ref inner) => InlineeIterator(inner.inlinees()),
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

#[derive(Clone, Debug)]
enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug)]
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl Default for LineIterator<'_> {
    fn default() -> Self {
        LineIterator {
            inner: LineIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}

/// An inlined function that can evaluate to line information.
#[derive(Clone, Debug)]
pub struct Inlinee<'a>(c13::C13Inlinee<'a>);

impl<'a> Inlinee<'a> {
    /// The index of this inlinee in the `IdInformation` stream (IPI).
    pub fn index(&self) -> IdIndex {
        self.0.index()
    }

    /// Returns an iterator over line records for an inline site.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(
        &self,
        parent_offset: PdbInternalSectionOffset,
        inline_site: &InlineSiteSymbol<'a>,
    ) -> InlineeLineIterator<'a> {
        InlineeLineIterator(self.0.lines(parent_offset, inline_site))
    }
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug, Default)]
pub struct InlineeIterator<'a>(c13::C13InlineeIterator<'a>);

impl<'a> FallibleIterator for InlineeIterator<'a> {
    type Item = Inlinee<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        self.0.next().map(|opt| opt.map(Inlinee))
    }
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug, Default)]
pub struct InlineeLineIterator<'a>(c13::C13InlineeLineIterator<'a>);

impl<'a> FallibleIterator for InlineeLineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        self.0.next()
    }
}

#[derive(Clone, Debug)]
enum FileIteratorInner<'a> {
    C13(c13::C13FileIterator<'a>),
}

/// An iterator over file records in a module.
#[derive(Clone, Debug)]
pub struct FileIterator<'a> {
    inner: FileIteratorInner<'a>,
}

impl Default for FileIterator<'_> {
    fn default() -> Self {
        FileIterator {
            inner: FileIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for FileIterator<'a> {
    type Item = FileInfo<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            FileIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<|endoftext|>


<commit_before>use iron::{Handler, Response, Request, IronResult, Url, Error};
use typemap::Assoc;
use trie::Trie;

/// Exposes the original, unmodified path to be stored in `Request::extensions`.
pub struct OriginalUrl;
impl Assoc<Url> for OriginalUrl {}

/// `Mount` is a simple mounting middleware.
///
/// Mounting allows you to install a handler on a route and have it receive requests as if they
/// are relative to that route. For example, a handler mounted on `/foo/` will receive
/// requests like `/foo/bar` as if they are just `/bar`. Iron's mounting middleware allows
/// you to specify multiple mountings using one middleware instance. Requests that pass through
/// the mounting middleware are passed along to the mounted handler that best matches the request's
/// path. `Request::url` is modified so that requests appear to be relative to the mounted handler's route.
///
/// Mounted handlers may also access the *original* URL by requesting the `OriginalUrl` key
/// from `Request::extensions`.
pub struct Mount {
    inner: Trie<String, Match>
}

struct Match {
    handler: Box<Handler + Send + Sync>,
    length: uint
}

/// The error returned by `Mount` when a request doesn't match any mounted handlers.
#[deriving(Show)]
pub struct NoMatch;

impl Error for NoMatch {
    fn name(&self) -> &'static str { "No Match" }
}

impl Mount {
    /// Creates a new instance of `Mount`.
    pub fn new() -> Mount {
        Mount {
            inner: Trie::new()
        }
    }

    /// Mounts a given `Handler` onto a route.
    ///
    /// This method may be called multiple times with different routes.
    /// For a given request, the *most specific* handler will be selected.
    ///
    /// Existing handlers on the same route will be overwritten.
    pub fn mount<H: Handler>(&mut self, route: &str, handler: H) -> &mut Mount {
        // Parse the route into a list of strings. The unwrap is safe because strs are UTF-8.
        let key: Vec<String> = Path::new(route).str_components().map(|s| s.unwrap().to_string()).collect();

        // Insert a match struct into the trie.
        self.inner.insert(key.as_slice(), Match {
            handler: box handler as Box<Handler + Send + Sync>,
            length: key.len()
        });
        self
    }
}

impl Handler for Mount {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Find the matching handler.
        let matched = {
            // Extract the request path.
            let path = req.url.path.as_slice();

            // If present, remove the trailing empty string (which represents a trailing slash).
            // If it isn't removed the path will never match anything, because
            // Path::str_components ignores trailing slashes and will never create routes
            // ending in "".
            let key = match path.last() {
                Some(s) if s.is_empty() => path.slice_to(path.len() - 1),
                _ => path
            };

            // Search the Trie for the nearest most specific match.
            match self.inner.find_ancestor(key) {
                Some(matched) => matched,
                None => return Err(box NoMatch as Box<Error + Send>)
            }
        };

        // We have a match, so fire off the child.
        // If another mount middleware hasn't already, insert the unmodified url
        // into the extensions as the "original url".
        let is_outer_mount = !req.extensions.contains::<OriginalUrl, Url>();
        if is_outer_mount {
            req.extensions.insert::<OriginalUrl, Url>(req.url.clone());
        }

        // Remove the prefix from the request's path before passing it to the mounted handler.
        // If the prefix is entirely removed and no trailing slash was present, the new path
        // will be the empty list. For the purposes of redirection, conveying that the path
        // did not include a trailing slash is more important than providing a non-empty list.
        req.url.path = req.url.path.as_slice().slice_from(matched.length).to_vec();

        let res = matched.handler.call(req);

        // Reverse the URL munging, for future middleware.
        req.url = match req.extensions.find::<OriginalUrl, Url>() {
            Some(original) => original.clone(),
            None => fail!("OriginalUrl unexpectedly removed from req.extensions.")
        };

        // If this mount middleware is the outermost mount middleware,
        // remove the original url from the extensions map to prevent leakage.
        if is_outer_mount {
            req.extensions.remove::<OriginalUrl, Url>();
        }

        res
    }
}

<commit_msg>(fix) Remove unnecessary Send bound in Error casting.<commit_after>use iron::{Handler, Response, Request, IronResult, Url, Error};
use typemap::Assoc;
use trie::Trie;

/// Exposes the original, unmodified path to be stored in `Request::extensions`.
pub struct OriginalUrl;
impl Assoc<Url> for OriginalUrl {}

/// `Mount` is a simple mounting middleware.
///
/// Mounting allows you to install a handler on a route and have it receive requests as if they
/// are relative to that route. For example, a handler mounted on `/foo/` will receive
/// requests like `/foo/bar` as if they are just `/bar`. Iron's mounting middleware allows
/// you to specify multiple mountings using one middleware instance. Requests that pass through
/// the mounting middleware are passed along to the mounted handler that best matches the request's
/// path. `Request::url` is modified so that requests appear to be relative to the mounted handler's route.
///
/// Mounted handlers may also access the *original* URL by requesting the `OriginalUrl` key
/// from `Request::extensions`.
pub struct Mount {
    inner: Trie<String, Match>
}

struct Match {
    handler: Box<Handler + Send + Sync>,
    length: uint
}

/// The error returned by `Mount` when a request doesn't match any mounted handlers.
#[deriving(Show)]
pub struct NoMatch;

impl Error for NoMatch {
    fn name(&self) -> &'static str { "No Match" }
}

impl Mount {
    /// Creates a new instance of `Mount`.
    pub fn new() -> Mount {
        Mount {
            inner: Trie::new()
        }
    }

    /// Mounts a given `Handler` onto a route.
    ///
    /// This method may be called multiple times with different routes.
    /// For a given request, the *most specific* handler will be selected.
    ///
    /// Existing handlers on the same route will be overwritten.
    pub fn mount<H: Handler>(&mut self, route: &str, handler: H) -> &mut Mount {
        // Parse the route into a list of strings. The unwrap is safe because strs are UTF-8.
        let key: Vec<String> = Path::new(route).str_components().map(|s| s.unwrap().to_string()).collect();

        // Insert a match struct into the trie.
        self.inner.insert(key.as_slice(), Match {
            handler: box handler as Box<Handler + Send + Sync>,
            length: key.len()
        });
        self
    }
}

impl Handler for Mount {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Find the matching handler.
        let matched = {
            // Extract the request path.
            let path = req.url.path.as_slice();

            // If present, remove the trailing empty string (which represents a trailing slash).
            // If it isn't removed the path will never match anything, because
            // Path::str_components ignores trailing slashes and will never create routes
            // ending in "".
            let key = match path.last() {
                Some(s) if s.is_empty() => path.slice_to(path.len() - 1),
                _ => path
            };

            // Search the Trie for the nearest most specific match.
            match self.inner.find_ancestor(key) {
                Some(matched) => matched,
                None => return Err(box NoMatch as Box<Error>)
            }
        };

        // We have a match, so fire off the child.
        // If another mount middleware hasn't already, insert the unmodified url
        // into the extensions as the "original url".
        let is_outer_mount = !req.extensions.contains::<OriginalUrl, Url>();
        if is_outer_mount {
            req.extensions.insert::<OriginalUrl, Url>(req.url.clone());
        }

        // Remove the prefix from the request's path before passing it to the mounted handler.
        // If the prefix is entirely removed and no trailing slash was present, the new path
        // will be the empty list. For the purposes of redirection, conveying that the path
        // did not include a trailing slash is more important than providing a non-empty list.
        req.url.path = req.url.path.as_slice().slice_from(matched.length).to_vec();

        let res = matched.handler.call(req);

        // Reverse the URL munging, for future middleware.
        req.url = match req.extensions.find::<OriginalUrl, Url>() {
            Some(original) => original.clone(),
            None => fail!("OriginalUrl unexpectedly removed from req.extensions.")
        };

        // If this mount middleware is the outermost mount middleware,
        // remove the original url from the extensions map to prevent leakage.
        if is_outer_mount {
            req.extensions.remove::<OriginalUrl, Url>();
        }

        res
    }
}

<|endoftext|>


<commit_before>// Copyright 2015 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use std::ops::{
    Add,
    Mul,
};
use num::complex::{Complex32, Complex64};
use attribute::Transpose;
use default::Default;
use matrix::ops::*;
use matrix::Matrix;
use math::Mat;
use vector::ops::*;

impl<'a, T> Add for &'a Matrix<T>
    where T: Axpy + Copy + Default
{
    type Output = Mat<T>;

    fn add(self, b: &Matrix<T>) -> Mat<T> {
        if self.cols() != b.cols() || self.rows() != b.rows() {
            panic!("Dimension mismatch")
        }

        let scale = Default::one();
        let mut result = Mat::from(self);
        Axpy::axpy_mat(&scale, b, &mut result);
        result
    }
}

impl<'a, T> Mul<T> for &'a Matrix<T>
    where T: Sized + Copy + Scal
{
    type Output = Mat<T>;

    fn mul(self, alpha: T) -> Mat<T> {
        let mut result = Mat::from(self);
        Scal::scal_mat(&alpha, &mut result);
        result
    }
}

macro_rules! left_scale(($($t: ident), +) => (
    $(
        impl<'a> Mul<&'a Matrix<$t>> for $t
        {
            type Output = Mat<$t>;

            fn mul(self, x: &'a Matrix<$t>) -> Mat<$t> {
                let mut result = Mat::from(x);
                Scal::scal_mat(&self, &mut result);
                result
            }
        }
    )+
));

left_scale!(f32, f64, Complex32, Complex64);

impl<'a, T> Mul<&'a Matrix<T>> for &'a Matrix<T>
    where T: Default + Gemm,
{
    type Output = Mat<T>;

    fn mul(self, b: &'a Matrix<T>) -> Mat<T> {
        if self.cols() != b.rows() {
            panic!("Dimension mismatch");
        }

        let n = self.rows() as usize;
        let m = b.cols() as usize;
        let mut result = Mat::new(n, m);
        let t = Transpose::NoTrans;

        Gemm::gemm(&Default::one(), t, self, t, b, &Default::zero(), &mut result);
        result
    }
}

#[cfg(test)]
mod tests {
    use Matrix;
    use math::Mat;

    #[test]
    fn add() {
        let a = mat![1.0, 2.0; 3.0, 4.0];
        let b = mat![-1.0, 3.0; 1.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            ar + br
        };

        assert_eq!(c, mat![0.0, 5.0; 4.0, 5.0]);
    }

    #[test]
    fn scale() {
        let x = mat![1f32, 2f32; 3f32, 4f32];
        let xr = &x as &Matrix<_>;

        let y = xr * 3.0;
        let z = 3.0 * xr;
        assert_eq!(y, mat![3f32, 6f32; 9f32, 12f32]);
        assert_eq!(z, y);
    }

    #[test]
    fn mul() {
        let a = mat![1.0, 2.0; 3.0, 4.0];
        let b = mat![-1.0, 3.0; 1.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            ar * br
        };

        assert_eq!(c, mat![1.0, 5.0; 1.0, 13.0]);
    }
}
<commit_msg>Multiply transpose<commit_after>// Copyright 2015 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use std::ops::{
    Add,
    Mul,
};
use num::complex::{Complex32, Complex64};
use attribute::Transpose;
use default::Default;
use math::Trans;
use matrix::ops::*;
use matrix::Matrix;
use math::Mat;
use vector::ops::*;

impl<'a, T> Add for &'a Matrix<T>
    where T: Axpy + Copy + Default
{
    type Output = Mat<T>;

    fn add(self, b: &Matrix<T>) -> Mat<T> {
        if self.cols() != b.cols() || self.rows() != b.rows() {
            panic!("Dimension mismatch")
        }

        let scale = Default::one();
        let mut result = Mat::from(self);
        Axpy::axpy_mat(&scale, b, &mut result);
        result
    }
}

impl<'a, T> Mul<T> for &'a Matrix<T>
    where T: Sized + Copy + Scal
{
    type Output = Mat<T>;

    fn mul(self, alpha: T) -> Mat<T> {
        let mut result = Mat::from(self);
        Scal::scal_mat(&alpha, &mut result);
        result
    }
}

macro_rules! left_scale(($($t: ident), +) => (
    $(
        impl<'a> Mul<&'a Matrix<$t>> for $t
        {
            type Output = Mat<$t>;

            fn mul(self, x: &'a Matrix<$t>) -> Mat<$t> {
                let mut result = Mat::from(x);
                Scal::scal_mat(&self, &mut result);
                result
            }
        }
    )+
));

left_scale!(f32, f64, Complex32, Complex64);

impl<'a, T> Mul<&'a Matrix<T>> for &'a Matrix<T>
    where T: Default + Gemm,
{
    type Output = Mat<T>;

    fn mul(self, b: &'a Matrix<T>) -> Mat<T> {
        if self.cols() != b.rows() {
            panic!("Dimension mismatch");
        }

        let n = self.rows() as usize;
        let m = b.cols() as usize;
        let mut result = Mat::new(n, m);
        let t = Transpose::NoTrans;

        Gemm::gemm(&Default::one(), t, self, t, b, &Default::zero(), &mut result);
        result
    }
}

impl<'a, T> Mul<&'a Matrix<T>> for Trans<&'a Matrix<T>>
    where T: Default + Gemm,
{
    type Output = Mat<T>;

    fn mul(self, b: &'a Matrix<T>) -> Mat<T> {
        let (a, at) = match self {
            Trans::T(a) => (a, Transpose::Trans),
            Trans::H(a) => (a, Transpose::ConjTrans),
        };

        if a.rows() != b.rows() {
            panic!("Dimension mismatch");
        }

        let n = a.cols() as usize;
        let m = b.cols() as usize;
        let mut result = Mat::new(n, m);
        let bt = Transpose::NoTrans;

        Gemm::gemm(&Default::one(), at, a, bt, b, &Default::zero(), &mut result);
        result
    }
}

impl<'a, T> Mul<Trans<&'a Matrix<T>>> for &'a Matrix<T>
    where T: Default + Gemm,
{
    type Output = Mat<T>;

    fn mul(self, rhs: Trans<&'a Matrix<T>>) -> Mat<T> {
        let (b, bt) = match rhs {
            Trans::T(a) => (a, Transpose::Trans),
            Trans::H(a) => (a, Transpose::ConjTrans),
        };

        if self.cols() != b.cols() {
            panic!("Dimension mismatch");
        }

        let n = self.rows() as usize;
        let m = b.rows() as usize;
        let mut result = Mat::new(n, m);
        let at = Transpose::NoTrans;

        Gemm::gemm(&Default::one(), at, self, bt, b, &Default::zero(), &mut result);
        result
    }
}

impl<'a, T> Mul<Trans<&'a Matrix<T>>> for Trans<&'a Matrix<T>>
    where T: Default + Gemm,
{
    type Output = Mat<T>;

    fn mul(self, rhs: Trans<&'a Matrix<T>>) -> Mat<T> {
        let (a, at) = match self {
            Trans::T(a) => (a, Transpose::Trans),
            Trans::H(a) => (a, Transpose::ConjTrans),
        };

        let (b, bt) = match rhs {
            Trans::T(a) => (a, Transpose::Trans),
            Trans::H(a) => (a, Transpose::ConjTrans),
        };

        if self.rows() != b.cols() {
            panic!("Dimension mismatch");
        }

        let n = self.cols() as usize;
        let m = b.rows() as usize;
        let mut result = Mat::new(n, m);

        Gemm::gemm(&Default::one(), at, a, bt, b, &Default::zero(), &mut result);
        result
    }
}

#[cfg(test)]
mod tests {
    use Matrix;
    use math::Mat;
    use math::Marker::T;

    #[test]
    fn add() {
        let a = mat![1.0, 2.0; 3.0, 4.0];
        let b = mat![-1.0, 3.0; 1.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            ar + br
        };

        assert_eq!(c, mat![0.0, 5.0; 4.0, 5.0]);
    }

    #[test]
    fn scale() {
        let x = mat![1f32, 2f32; 3f32, 4f32];
        let xr = &x as &Matrix<_>;

        let y = xr * 3.0;
        let z = 3.0 * xr;
        assert_eq!(y, mat![3f32, 6f32; 9f32, 12f32]);
        assert_eq!(z, y);
    }

    #[test]
    fn mul() {
        let a = mat![1.0, 2.0; 3.0, 4.0];
        let b = mat![-1.0, 3.0; 1.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            ar * br
        };

        assert_eq!(c, mat![1.0, 5.0; 1.0, 13.0]);
    }

    #[test]
    fn left_mul_trans() {
        let a = mat![1.0, 3.0; 2.0, 4.0];
        let b = mat![-1.0, 3.0; 1.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            (ar ^ T) * br
        };

        assert_eq!(c, mat![1.0, 5.0; 1.0, 13.0]);
    }

    #[test]
    fn right_mul_trans() {
        let a = mat![1.0, 2.0; 3.0, 4.0];
        let b = mat![-1.0, 1.0; 3.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            ar * (br ^ T)
        };

        assert_eq!(c, mat![1.0, 5.0; 1.0, 13.0]);
    }

    #[test]
    fn mul_trans() {
        let a = mat![1.0, 3.0; 2.0, 4.0];
        let b = mat![-1.0, 1.0; 3.0, 1.0];

        let c = {
            let ar = &a as &Matrix<_>;
            let br = &b as &Matrix<_>;
            (ar ^ T) * (br ^ T)
        };

        assert_eq!(c, mat![1.0, 5.0; 1.0, 13.0]);
    }
}
<|endoftext|>


<commit_before>
/// Mode of input similar to Vim input mode.
///
/// In each mode the key will have a different meaning
enum InputMode{
    /// Default game mode
    Default,
    /// Move cursor freely around to identify things
    Explore,
    /// Menu
    Menu,
    /// Yes or no question
    YesOrNo,
    /// Help files
    Help,
}

pub struct InputHandler{
    mode : InputMode,
}

impl InputHandler{
    pub fn new() -> InputHandler{
        InputHandler{
            mode : InputMode::Default,
        }
    }

    pub fn process_key(&self, key: char){

        match key {
            'h' => info!("west"),
            'j' => info!("south"),
            'k' => info!("north"),
            'l' => info!("left"),
            'y' => info!("left"),
            'u' => info!("left"),
            'b' => info!("left"),
            'n' => info!("left"),
             _  => info!("error"),
        }

    }

}

<commit_msg>add change input format<commit_after>
/// Mode of input similar to Vim input mode.
///
/// In each mode the key will have a different meaning
pub enum InputMode{
    /// Default game mode
    Default,
    /// Move cursor freely around to identify things
    Explore,
    /// Menu
    Menu,
    /// Yes or no question
    YesOrNo,
    /// Help files
    Help,
}

pub struct InputHandler{
    mode : InputMode,
}

impl InputHandler{
    pub fn new() -> InputHandler{
        InputHandler{
            mode : InputMode::Default,
        }
    }

    pub fn change_mode(&mut self, new_mode: InputMode ){
        self.mode = new_mode;
    }

    pub fn process_key(&self, key: char){

        match key {
            'h' => info!("west"),
            'j' => info!("south"),
            'k' => info!("north"),
            'l' => info!("left"),
            'y' => info!("left"),
            'u' => info!("left"),
            'b' => info!("left"),
            'n' => info!("left"),
             _  => info!("error"),
        }

    }

}

<|endoftext|>


<commit_before>//! Performs the translation from a wasm module in binary format to the in-memory representation
//! of the Cretonne IL. More particularly, it translates the code of all the functions bodies and
//! interacts with a runtime implementing the [`WasmRuntime`](trait.WasmRuntime.html) trait to
//! deal with tables, globals and linear memory.
//!
//! The crate provides a `DummyRuntime` trait that will allow to translate the code of the
//! functions but will fail at execution. You should use
//! [`wasmstandalone::StandaloneRuntime`](../wasmstandalone/struct.StandaloneRuntime.html) to be
//! able to execute the translated code.
//!
//! The main function of this module is [`translate_module`](fn.translate_module.html).

#![deny(missing_docs)]

extern crate wasmparser;
extern crate cton_frontend;
extern crate cretonne;

mod code_translator;
mod module_translator;
mod runtime;
mod sections_translator;
mod state;
mod translation_utils;

pub use module_translator::{translate_module, TranslationResult};
pub use runtime::{FuncEnvironment, WasmRuntime, DummyRuntime};
pub use translation_utils::{FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, SignatureIndex,
                            Global, GlobalInit, Table, Memory};
<commit_msg>Publically declare GlobalValue.<commit_after>//! Performs the translation from a wasm module in binary format to the in-memory representation
//! of the Cretonne IL. More particularly, it translates the code of all the functions bodies and
//! interacts with a runtime implementing the [`WasmRuntime`](trait.WasmRuntime.html) trait to
//! deal with tables, globals and linear memory.
//!
//! The crate provides a `DummyRuntime` trait that will allow to translate the code of the
//! functions but will fail at execution. You should use
//! [`wasmstandalone::StandaloneRuntime`](../wasmstandalone/struct.StandaloneRuntime.html) to be
//! able to execute the translated code.
//!
//! The main function of this module is [`translate_module`](fn.translate_module.html).

#![deny(missing_docs)]

extern crate wasmparser;
extern crate cton_frontend;
extern crate cretonne;

mod code_translator;
mod module_translator;
mod runtime;
mod sections_translator;
mod state;
mod translation_utils;

pub use module_translator::{translate_module, TranslationResult};
pub use runtime::{FuncEnvironment, WasmRuntime, DummyRuntime, GlobalValue};
pub use translation_utils::{FunctionIndex, GlobalIndex, TableIndex, MemoryIndex, SignatureIndex,
                            Global, GlobalInit, Table, Memory};
<|endoftext|>


<commit_before>use crate::data_types::SolrReferenceSummary;

use regex::Regex;

use std::collections::HashMap;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::do_solr_request;

#[derive(Serialize, Deserialize, Debug)]
pub struct RefSearchMatch {
    pub id: String,
    pub authors_abbrev: Option<String>,
    pub title: Option<String>,
    pub citation: Option<String>,
    pub publication_year: Option<u32>,
    pub hl: SolrMatchHighlight,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefSearchResponse {
    pub docs: Vec<RefSearchRes>,
}

#[derive(Deserialize, Debug)]
struct SolrRefSearchResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrRefSearchResponse,
}

#[derive(Serialize, Deserialize, Debug)]
struct RefSearchRes {
    pub id: String,
    pub authors_abbrev: Option<String>,
    pub citation: Option<String>,
    pub title: Option<String>,
    pub publication_year: Option<u32>,
}

pub fn ref_complete(config: &ServerConfig, q: &str)
                    -> Result<Vec<SolrReferenceSummary>, String>
{
    if let Some(refs_url) = make_refs_url(config, q, &["title", "citation", "authors"]) {
        let res = do_solr_request(&refs_url)?;

        match serde_json::from_reader(res) {
            Ok(container) => {
                let solr_response_container: SolrRefResponseContainer = container;
                Ok(solr_response_container.response.docs)
            },
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        // query string is too short to do search
        Ok(vec![])
    }
}

fn make_refs_url(config: &ServerConfig, q: &str, query_field_names: &[&str])
                 -> Option<String>
{
    let mut refs_url =
        config.solr_url.to_owned() + "/refs/select?wt=json&q=";

    let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
    let id_re = Regex::new(id_re_string).unwrap();

    if let Some(captures) = id_re.captures(q) {
        let prefix =
            if let Some(prefix_capture) = captures.name("prefix") {
                prefix_capture.as_str()
            } else {
                "PMID"
            };
        let accession = captures.name("rest").unwrap().as_str();
        refs_url += "id:";
        refs_url += prefix;
        refs_url += r"\:";
        refs_url += accession;
    } else {
        let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
        let lower_q = substring(&q.to_lowercase(), 200);

        let clean_words: Vec<String> =
            Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
            .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

        if clean_words.is_empty() {
            return None
        }

        let clean_words_length = clean_words.len();
        let mut clean_words_for_url = String::new();

        for (i, word) in clean_words.iter().enumerate() {
            if i == clean_words_length - 1 {
                clean_words_for_url += &format!("{} {}*", word, word);
            } else {
                clean_words_for_url += &format!("{} ", word);
            }
        }

        let url_parts =
            query_field_names
            .iter()
            .map(|field_name| {
                let weight = if *field_name == "title" {
                    2.0
                } else {
                    0.5
                };
                format!("{}:({})^{}", field_name, clean_words_for_url, weight)
            })
            .collect::<Vec<String>>();

        refs_url += &url_parts.join(" OR ");

        for word in clean_words {
            if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                if let Ok(num) = word.parse::<u32>() {
                    refs_url += &format!(" OR publication_year:{}^20", num);
                }
            }
        }
    }

    Some(refs_url)
}

pub fn search_refs(config: &ServerConfig, q: &str) -> Result<Vec<RefSearchMatch>, String> {
    let hl_field_names = ["title", "citation", "authors", "pubmed_abstract"];
    let maybe_url = make_refs_url(config, q, &hl_field_names);
    if let Some(mut url) = maybe_url {
        url += &format!("&hl=on&hl.fl={},publication_year&fl=id,authors_abbrev,title,publication_year",
                        hl_field_names.join(","));
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => {
                let response_container: SolrRefSearchResponseContainer = container;
                let mut hl_by_id = response_container.highlighting;
                let str_from = |s| String::from(s);
                let matches: Vec<RefSearchMatch> = response_container.response.docs
                    .iter().map(|doc| RefSearchMatch {
                        id: String::from(&doc.id),
                        citation: doc.citation.as_ref().map(str_from),
                        authors_abbrev: doc.authors_abbrev.as_ref().map(str_from),
                        title: doc.title.as_ref().map(str_from),
                        publication_year: doc.publication_year,
                        hl: hl_by_id.remove(doc.id.as_str())
                            .unwrap_or_else(HashMap::new),
                    }).collect();
                Ok(matches)
            },
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<commit_msg>Use lazy_static to make RE for ref query cleaning<commit_after>use crate::data_types::SolrReferenceSummary;

use regex::Regex;

use std::collections::HashMap;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::do_solr_request;

lazy_static! {
    static ref CLEAN_WORDS_RE: Regex = Regex::new(r"([\w\d\-]+)").unwrap();
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RefSearchMatch {
    pub id: String,
    pub authors_abbrev: Option<String>,
    pub title: Option<String>,
    pub citation: Option<String>,
    pub publication_year: Option<u32>,
    pub hl: SolrMatchHighlight,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefSearchResponse {
    pub docs: Vec<RefSearchRes>,
}

#[derive(Deserialize, Debug)]
struct SolrRefSearchResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrRefSearchResponse,
}

#[derive(Serialize, Deserialize, Debug)]
struct RefSearchRes {
    pub id: String,
    pub authors_abbrev: Option<String>,
    pub citation: Option<String>,
    pub title: Option<String>,
    pub publication_year: Option<u32>,
}

pub fn ref_complete(config: &ServerConfig, q: &str)
                    -> Result<Vec<SolrReferenceSummary>, String>
{
    if let Some(refs_url) = make_refs_url(config, q, &["title", "citation", "authors"]) {
        let res = do_solr_request(&refs_url)?;

        match serde_json::from_reader(res) {
            Ok(container) => {
                let solr_response_container: SolrRefResponseContainer = container;
                Ok(solr_response_container.response.docs)
            },
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        // query string is too short to do search
        Ok(vec![])
    }
}

fn make_refs_url(config: &ServerConfig, q: &str, query_field_names: &[&str])
                 -> Option<String>
{
    let mut refs_url =
        config.solr_url.to_owned() + "/refs/select?wt=json&q=";

    let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
    let id_re = Regex::new(id_re_string).unwrap();

    if let Some(captures) = id_re.captures(q) {
        let prefix =
            if let Some(prefix_capture) = captures.name("prefix") {
                prefix_capture.as_str()
            } else {
                "PMID"
            };
        let accession = captures.name("rest").unwrap().as_str();
        refs_url += "id:";
        refs_url += prefix;
        refs_url += r"\:";
        refs_url += accession;
    } else {
        let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
        let lower_q = substring(&q.to_lowercase(), 200);

        let clean_words: Vec<String> =
            CLEAN_WORDS_RE.captures_iter(&lower_q)
            .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

        if clean_words.is_empty() {
            return None
        }

        let clean_words_length = clean_words.len();
        let mut clean_words_for_url = String::new();

        for (i, word) in clean_words.iter().enumerate() {
            if i == clean_words_length - 1 {
                clean_words_for_url += &format!("{} {}*", word, word);
            } else {
                clean_words_for_url += &format!("{} ", word);
            }
        }

        let url_parts =
            query_field_names
            .iter()
            .map(|field_name| {
                let weight = if *field_name == "title" {
                    2.0
                } else {
                    0.5
                };
                format!("{}:({})^{}", field_name, clean_words_for_url, weight)
            })
            .collect::<Vec<String>>();

        refs_url += &url_parts.join(" OR ");

        for word in clean_words {
            if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                if let Ok(num) = word.parse::<u32>() {
                    refs_url += &format!(" OR publication_year:{}^20", num);
                }
            }
        }
    }

    Some(refs_url)
}

pub fn search_refs(config: &ServerConfig, q: &str) -> Result<Vec<RefSearchMatch>, String> {
    let hl_field_names = ["title", "citation", "authors", "pubmed_abstract"];
    let maybe_url = make_refs_url(config, q, &hl_field_names);
    if let Some(mut url) = maybe_url {
        url += &format!("&hl=on&hl.fl={},publication_year&fl=id,authors_abbrev,title,publication_year",
                        hl_field_names.join(","));
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => {
                let response_container: SolrRefSearchResponseContainer = container;
                let mut hl_by_id = response_container.highlighting;
                let str_from = |s| String::from(s);
                let matches: Vec<RefSearchMatch> = response_container.response.docs
                    .iter().map(|doc| RefSearchMatch {
                        id: String::from(&doc.id),
                        citation: doc.citation.as_ref().map(str_from),
                        authors_abbrev: doc.authors_abbrev.as_ref().map(str_from),
                        title: doc.title.as_ref().map(str_from),
                        publication_year: doc.publication_year,
                        hl: hl_by_id.remove(doc.id.as_str())
                            .unwrap_or_else(HashMap::new),
                    }).collect();
                Ok(matches)
            },
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<|endoftext|>


<commit_before>//! Licensed under the Apache License, Version 2.0
//! https://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! https://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.
#![no_std]

use core::iter;
use itertools as it;
use crate::it::Itertools;
use crate::it::interleave;
use crate::it::intersperse;
use crate::it::intersperse_with;
use crate::it::multizip;
use crate::it::free::put_back;
use crate::it::iproduct;
use crate::it::izip;
use crate::it::chain;

#[test]
fn product2() {
    let s = "αβ";

    let mut prod = iproduct!(s.chars(), 0..2);
    assert!(prod.next() == Some(('α', 0)));
    assert!(prod.next() == Some(('α', 1)));
    assert!(prod.next() == Some(('β', 0)));
    assert!(prod.next() == Some(('β', 1)));
    assert!(prod.next() == None);
}

#[test]
fn product_temporary() {
    for (_x, _y, _z) in iproduct!(
        [0, 1, 2].iter().cloned(),
        [0, 1, 2].iter().cloned(),
        [0, 1, 2].iter().cloned())
    {
        // ok
    }
}

#[test]
fn izip_macro() {
    let mut zip = izip!(2..3);
    assert!(zip.next() == Some(2));
    assert!(zip.next().is_none());

    let mut zip = izip!(0..3, 0..2, 0..2i8);
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [isize; 0] = [];
    let mut zip = izip!(0..3, 0..2, 0..2i8, &xs);
    assert!(zip.next().is_none());
}

#[test]
fn izip2() {
    let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
    let _zip2: iter::Zip<_, _> = izip!(1.., 2.., );
}

#[test]
fn izip3() {
    let mut zip: iter::Map<iter::Zip<_, _>, _> = izip!(0..3, 0..2, 0..2i8);
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());
}

#[test]
fn multizip3() {
    let mut zip = multizip((0..3, 0..2, 0..2i8));
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [isize; 0] = [];
    let mut zip = multizip((0..3, 0..2, 0..2i8, xs.iter()));
    assert!(zip.next().is_none());

    for (_, _, _, _, _) in multizip((0..3, 0..2, xs.iter(), &xs, xs.to_vec())) {
        /* test compiles */
    }
}

#[test]
fn chain_macro() {
    let mut chain = chain!(2..3);
    assert!(chain.next() == Some(2));
    assert!(chain.next().is_none());

    let mut chain = chain!(0..2, 2..3, 3..5i8);
    for i in 0..5i8 {
        assert_eq!(Some(i), chain.next());
    }
    assert!(chain.next().is_none());

    let mut chain = chain!();
    assert_eq!(chain.next(), Option::<()>::None);
}

#[test]
fn chain2() {
    let _ = chain!(1.., 2..);
    let _ = chain!(1.., 2.., );
}

#[test]
fn write_to() {
    let xs = [7, 9, 8];
    let mut ys = [0; 5];
    let cnt = ys.iter_mut().set_from(xs.iter().copied());
    assert!(cnt == xs.len());
    assert!(ys == [7, 9, 8, 0, 0]);

    let cnt = ys.iter_mut().set_from(0..10);
    assert!(cnt == ys.len());
    assert!(ys == [0, 1, 2, 3, 4]);
}

#[test]
fn test_interleave() {
    let xs: [u8; 0]  = [];
    let ys = [7u8, 9, 8, 10];
    let zs = [2u8, 77];
    let it = interleave(xs.iter(), ys.iter());
    it::assert_equal(it, ys.iter());

    let rs = [7u8, 2, 9, 77, 8, 10];
    let it = interleave(ys.iter(), zs.iter());
    it::assert_equal(it, rs.iter());
}

#[test]
fn test_intersperse() {
    let xs = [1u8, 2, 3];
    let ys = [1u8, 0, 2, 0, 3];
    let it = intersperse(&xs, &0);
    it::assert_equal(it, ys.iter());
}

#[test]
fn test_intersperse_with() {
    let xs = [1u8, 2, 3];
    let ys = [1u8, 10, 2, 10, 3];
    let i = 10;
    let it = intersperse_with(&xs, || &i);
    it::assert_equal(it, ys.iter());
}

#[allow(deprecated)]
#[test]
fn foreach() {
    let xs = [1i32, 2, 3];
    let mut sum = 0;
    xs.iter().foreach(|elt| sum += *elt);
    assert!(sum == 6);
}

#[test]
fn dropping() {
    let xs = [1, 2, 3];
    let mut it = xs.iter().dropping(2);
    assert_eq!(it.next(), Some(&3));
    assert!(it.next().is_none());
    let mut it = xs.iter().dropping(5);
    assert!(it.next().is_none());
}

#[test]
fn batching() {
    let xs = [0, 1, 2, 1, 3];
    let ys = [(0, 1), (2, 1)];

    // An iterator that gathers elements up in pairs
    let pit = xs.iter().cloned().batching(|it| {
               match it.next() {
                   None => None,
                   Some(x) => match it.next() {
                       None => None,
                       Some(y) => Some((x, y)),
                   }
               }
           });
    it::assert_equal(pit, ys.iter().cloned());
}

#[test]
fn test_put_back() {
    let xs = [0, 1, 1, 1, 2, 1, 3, 3];
    let mut pb = put_back(xs.iter().cloned());
    pb.next();
    pb.put_back(1);
    pb.put_back(0);
    it::assert_equal(pb, xs.iter().cloned());
}

#[allow(deprecated)]
#[test]
fn step() {
    it::assert_equal((0..10).step(1), 0..10);
    it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0));
    it::assert_equal((0..10).step(10), 0..1);
}

#[allow(deprecated)]
#[test]
fn merge() {
    it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10);
}

#[test]
fn repeatn() {
    let s = "α";
    let mut it = it::repeat_n(s, 3);
    assert_eq!(it.len(), 3);
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), None);
    assert_eq!(it.next(), None);
}

#[test]
fn count_clones() {
    // Check that RepeatN only clones N - 1 times.

    use core::cell::Cell;
    #[derive(PartialEq, Debug)]
    struct Foo {
        n: Cell<usize>
    }

    impl Clone for Foo
    {
        fn clone(&self) -> Self
        {
            let n = self.n.get();
            self.n.set(n + 1);
            Foo { n: Cell::new(n + 1) }
        }
    }

    for n in 0..10 {
        let f = Foo{n: Cell::new(0)};
        let it = it::repeat_n(f, n);
        // drain it
        let last = it.last();
        if n == 0 {
            assert_eq!(last, None);
        } else {
            assert_eq!(last, Some(Foo{n: Cell::new(n - 1)}));
        }
    }
}

#[test]
fn part() {
    let mut data = [7, 1, 1, 9, 1, 1, 3];
    let i = it::partition(&mut data, |elt| *elt >= 3);
    assert_eq!(i, 3);
    assert_eq!(data, [7, 3, 9, 1, 1, 1, 1]);

    let i = it::partition(&mut data, |elt| *elt == 1);
    assert_eq!(i, 4);
    assert_eq!(data, [1, 1, 1, 1, 9, 3, 7]);

    let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let i = it::partition(&mut data, |elt| *elt % 3 == 0);
    assert_eq!(i, 3);
    assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]);
}

#[test]
fn tree_fold1() {
    for i in 0..100 {
        assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y));
    }
}

#[test]
fn exactly_one() {
    assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
    assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4));
    assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
    assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0));
}

#[test]
fn at_most_one() {
    assert_eq!((0..10).filter(|&x| x == 2).at_most_one().unwrap(), Some(2));
    assert!((0..10).filter(|&x| x > 1 && x < 4).at_most_one().unwrap_err().eq(2..4));
    assert!((0..10).filter(|&x| x > 1 && x < 5).at_most_one().unwrap_err().eq(2..5));
    assert_eq!((0..10).filter(|&_| false).at_most_one().unwrap(), None);
}

#[test]
fn sum1() {
    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    assert_eq!(v[..0].iter().cloned().sum1::<i32>(), None);
    assert_eq!(v[1..2].iter().cloned().sum1::<i32>(), Some(1));
    assert_eq!(v[1..3].iter().cloned().sum1::<i32>(), Some(3));
    assert_eq!(v.iter().cloned().sum1::<i32>(), Some(55));
}

#[test]
fn product1() {
    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    assert_eq!(v[..0].iter().cloned().product1::<i32>(), None);
    assert_eq!(v[..1].iter().cloned().product1::<i32>(), Some(0));
    assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
    assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
}
<commit_msg>fix clippy::manual_map in tests<commit_after>//! Licensed under the Apache License, Version 2.0
//! https://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! https://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.
#![no_std]

use core::iter;
use itertools as it;
use crate::it::Itertools;
use crate::it::interleave;
use crate::it::intersperse;
use crate::it::intersperse_with;
use crate::it::multizip;
use crate::it::free::put_back;
use crate::it::iproduct;
use crate::it::izip;
use crate::it::chain;

#[test]
fn product2() {
    let s = "αβ";

    let mut prod = iproduct!(s.chars(), 0..2);
    assert!(prod.next() == Some(('α', 0)));
    assert!(prod.next() == Some(('α', 1)));
    assert!(prod.next() == Some(('β', 0)));
    assert!(prod.next() == Some(('β', 1)));
    assert!(prod.next() == None);
}

#[test]
fn product_temporary() {
    for (_x, _y, _z) in iproduct!(
        [0, 1, 2].iter().cloned(),
        [0, 1, 2].iter().cloned(),
        [0, 1, 2].iter().cloned())
    {
        // ok
    }
}

#[test]
fn izip_macro() {
    let mut zip = izip!(2..3);
    assert!(zip.next() == Some(2));
    assert!(zip.next().is_none());

    let mut zip = izip!(0..3, 0..2, 0..2i8);
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [isize; 0] = [];
    let mut zip = izip!(0..3, 0..2, 0..2i8, &xs);
    assert!(zip.next().is_none());
}

#[test]
fn izip2() {
    let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
    let _zip2: iter::Zip<_, _> = izip!(1.., 2.., );
}

#[test]
fn izip3() {
    let mut zip: iter::Map<iter::Zip<_, _>, _> = izip!(0..3, 0..2, 0..2i8);
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());
}

#[test]
fn multizip3() {
    let mut zip = multizip((0..3, 0..2, 0..2i8));
    for i in 0..2 {
        assert!((i as usize, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [isize; 0] = [];
    let mut zip = multizip((0..3, 0..2, 0..2i8, xs.iter()));
    assert!(zip.next().is_none());

    for (_, _, _, _, _) in multizip((0..3, 0..2, xs.iter(), &xs, xs.to_vec())) {
        /* test compiles */
    }
}

#[test]
fn chain_macro() {
    let mut chain = chain!(2..3);
    assert!(chain.next() == Some(2));
    assert!(chain.next().is_none());

    let mut chain = chain!(0..2, 2..3, 3..5i8);
    for i in 0..5i8 {
        assert_eq!(Some(i), chain.next());
    }
    assert!(chain.next().is_none());

    let mut chain = chain!();
    assert_eq!(chain.next(), Option::<()>::None);
}

#[test]
fn chain2() {
    let _ = chain!(1.., 2..);
    let _ = chain!(1.., 2.., );
}

#[test]
fn write_to() {
    let xs = [7, 9, 8];
    let mut ys = [0; 5];
    let cnt = ys.iter_mut().set_from(xs.iter().copied());
    assert!(cnt == xs.len());
    assert!(ys == [7, 9, 8, 0, 0]);

    let cnt = ys.iter_mut().set_from(0..10);
    assert!(cnt == ys.len());
    assert!(ys == [0, 1, 2, 3, 4]);
}

#[test]
fn test_interleave() {
    let xs: [u8; 0]  = [];
    let ys = [7u8, 9, 8, 10];
    let zs = [2u8, 77];
    let it = interleave(xs.iter(), ys.iter());
    it::assert_equal(it, ys.iter());

    let rs = [7u8, 2, 9, 77, 8, 10];
    let it = interleave(ys.iter(), zs.iter());
    it::assert_equal(it, rs.iter());
}

#[test]
fn test_intersperse() {
    let xs = [1u8, 2, 3];
    let ys = [1u8, 0, 2, 0, 3];
    let it = intersperse(&xs, &0);
    it::assert_equal(it, ys.iter());
}

#[test]
fn test_intersperse_with() {
    let xs = [1u8, 2, 3];
    let ys = [1u8, 10, 2, 10, 3];
    let i = 10;
    let it = intersperse_with(&xs, || &i);
    it::assert_equal(it, ys.iter());
}

#[allow(deprecated)]
#[test]
fn foreach() {
    let xs = [1i32, 2, 3];
    let mut sum = 0;
    xs.iter().foreach(|elt| sum += *elt);
    assert!(sum == 6);
}

#[test]
fn dropping() {
    let xs = [1, 2, 3];
    let mut it = xs.iter().dropping(2);
    assert_eq!(it.next(), Some(&3));
    assert!(it.next().is_none());
    let mut it = xs.iter().dropping(5);
    assert!(it.next().is_none());
}

#[test]
fn batching() {
    let xs = [0, 1, 2, 1, 3];
    let ys = [(0, 1), (2, 1)];

    // An iterator that gathers elements up in pairs
    let pit = xs
        .iter()
        .cloned()
        .batching(|it| it.next().and_then(|x| it.next().map(|y| (x, y))));
    it::assert_equal(pit, ys.iter().cloned());
}

#[test]
fn test_put_back() {
    let xs = [0, 1, 1, 1, 2, 1, 3, 3];
    let mut pb = put_back(xs.iter().cloned());
    pb.next();
    pb.put_back(1);
    pb.put_back(0);
    it::assert_equal(pb, xs.iter().cloned());
}

#[allow(deprecated)]
#[test]
fn step() {
    it::assert_equal((0..10).step(1), 0..10);
    it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0));
    it::assert_equal((0..10).step(10), 0..1);
}

#[allow(deprecated)]
#[test]
fn merge() {
    it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10);
}

#[test]
fn repeatn() {
    let s = "α";
    let mut it = it::repeat_n(s, 3);
    assert_eq!(it.len(), 3);
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), Some(s));
    assert_eq!(it.next(), None);
    assert_eq!(it.next(), None);
}

#[test]
fn count_clones() {
    // Check that RepeatN only clones N - 1 times.

    use core::cell::Cell;
    #[derive(PartialEq, Debug)]
    struct Foo {
        n: Cell<usize>
    }

    impl Clone for Foo
    {
        fn clone(&self) -> Self
        {
            let n = self.n.get();
            self.n.set(n + 1);
            Foo { n: Cell::new(n + 1) }
        }
    }

    for n in 0..10 {
        let f = Foo{n: Cell::new(0)};
        let it = it::repeat_n(f, n);
        // drain it
        let last = it.last();
        if n == 0 {
            assert_eq!(last, None);
        } else {
            assert_eq!(last, Some(Foo{n: Cell::new(n - 1)}));
        }
    }
}

#[test]
fn part() {
    let mut data = [7, 1, 1, 9, 1, 1, 3];
    let i = it::partition(&mut data, |elt| *elt >= 3);
    assert_eq!(i, 3);
    assert_eq!(data, [7, 3, 9, 1, 1, 1, 1]);

    let i = it::partition(&mut data, |elt| *elt == 1);
    assert_eq!(i, 4);
    assert_eq!(data, [1, 1, 1, 1, 9, 3, 7]);

    let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let i = it::partition(&mut data, |elt| *elt % 3 == 0);
    assert_eq!(i, 3);
    assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]);
}

#[test]
fn tree_fold1() {
    for i in 0..100 {
        assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y));
    }
}

#[test]
fn exactly_one() {
    assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
    assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4));
    assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
    assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0));
}

#[test]
fn at_most_one() {
    assert_eq!((0..10).filter(|&x| x == 2).at_most_one().unwrap(), Some(2));
    assert!((0..10).filter(|&x| x > 1 && x < 4).at_most_one().unwrap_err().eq(2..4));
    assert!((0..10).filter(|&x| x > 1 && x < 5).at_most_one().unwrap_err().eq(2..5));
    assert_eq!((0..10).filter(|&_| false).at_most_one().unwrap(), None);
}

#[test]
fn sum1() {
    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    assert_eq!(v[..0].iter().cloned().sum1::<i32>(), None);
    assert_eq!(v[1..2].iter().cloned().sum1::<i32>(), Some(1));
    assert_eq!(v[1..3].iter().cloned().sum1::<i32>(), Some(3));
    assert_eq!(v.iter().cloned().sum1::<i32>(), Some(55));
}

#[test]
fn product1() {
    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    assert_eq!(v[..0].iter().cloned().product1::<i32>(), None);
    assert_eq!(v[..1].iter().cloned().product1::<i32>(), Some(0));
    assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
    assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
}
<|endoftext|>


<commit_before>use super::super::ArgumentSplitter;
use std::fmt::{self, Display, Formatter};

#[derive(Debug, PartialEq)]
pub(crate) enum CaseError<'a> {
    NoBindVariable,
    NoConditional,
    ExtraBind(&'a str),
    ExtraVar(&'a str),
}

impl<'a> Display for CaseError<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            CaseError::NoBindVariable => write!(f, "no bind variable was supplied"),
            CaseError::NoConditional => write!(f, "no conditional statement was given"),
            CaseError::ExtraBind(value) => write!(f, "extra value, '{}', was given to bind", value),
            CaseError::ExtraVar(value) => {
                write!(f, "extra variable, '{}', was given to case", value)
            }
        }
    }
}

pub(crate) fn parse_case<'a>(
    data: &'a str,
) -> Result<(Option<&'a str>, Option<&'a str>, Option<String>), CaseError<'a>> {
    let mut splitter = ArgumentSplitter::new(data);
    // let argument = splitter.next().ok_or(CaseError::Empty)?;
    let mut argument = None;
    let mut binding = None;
    let mut conditional = None;
    loop {
        match splitter.next() {
            Some("@") => {
                binding = Some(splitter.next().ok_or(CaseError::NoBindVariable)?);
                match splitter.next() {
                    Some("if") => {
                        let string = splitter.collect::<Vec<_>>().join(" ");
                        if string.is_empty() {
                            return Err(CaseError::NoConditional);
                        }
                        conditional = Some(string);
                    }
                    Some(value) => return Err(CaseError::ExtraBind(value)),
                    None => (),
                }
            }
            Some("if") => {
                let string = splitter.collect::<Vec<_>>().join(" ");
                if string.is_empty() {
                    return Err(CaseError::NoConditional);
                }
                conditional = Some(string);
            }
            Some(inner) => if argument.is_none() {
                argument = Some(inner);
                continue;
            } else {
                return Err(CaseError::ExtraVar(inner));
            },
            None => (),
        }
        break;
    }

    Ok((argument, binding, conditional))
}

#[cfg(test)]
mod tests {
    use super::parse_case;
    #[test]
    fn case_parsing() {
        assert_eq!(
            Ok((Some("test"), Some("test"), Some("exists".into()))),
            parse_case("test @ test if exists")
        );
        assert_eq!(
            Ok((Some("test"), Some("test"), None)),
            parse_case("test @ test")
        );
        assert_eq!(Ok((Some("test"), None, None)), parse_case("test"));
    }
}
<commit_msg>Use iterators to join strings rather than join from a collected vec allocation<commit_after>use super::super::ArgumentSplitter;
use std::fmt::{self, Display, Formatter};

#[derive(Debug, PartialEq)]
pub(crate) enum CaseError<'a> {
    NoBindVariable,
    NoConditional,
    ExtraBind(&'a str),
    ExtraVar(&'a str),
}

impl<'a> Display for CaseError<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            CaseError::NoBindVariable => write!(f, "no bind variable was supplied"),
            CaseError::NoConditional => write!(f, "no conditional statement was given"),
            CaseError::ExtraBind(value) => write!(f, "extra value, '{}', was given to bind", value),
            CaseError::ExtraVar(value) => {
                write!(f, "extra variable, '{}', was given to case", value)
            }
        }
    }
}

pub(crate) fn parse_case<'a>(
    data: &'a str,
) -> Result<(Option<&'a str>, Option<&'a str>, Option<String>), CaseError<'a>> {
    let mut splitter = ArgumentSplitter::new(data);
    // let argument = splitter.next().ok_or(CaseError::Empty)?;
    let mut argument = None;
    let mut binding = None;
    let mut conditional = None;
    loop {
        match splitter.next() {
            Some("@") => {
                binding = Some(splitter.next().ok_or(CaseError::NoBindVariable)?);
                match splitter.next() {
                    Some("if") => {
                        // Joining by folding is more efficient than collecting into Vec and then joining
                        let mut string = splitter.fold(String::with_capacity(5), |mut state, element| {
                            state.push_str(element);
                            state.push(' ');
                            state
                        });
                        string.pop(); // Pop out the unneeded ' ' character
                        if string.is_empty() {
                            return Err(CaseError::NoConditional);
                        }
                        conditional = Some(string);
                    }
                    Some(value) => return Err(CaseError::ExtraBind(value)),
                    None => (),
                }
            }
            Some("if") => {
                // Joining by folding is more efficient than collecting into Vec and then joining
                let mut string = splitter.fold(String::with_capacity(5), |mut state, element| {
                    state.push_str(element);
                    state.push(' ');
                    state
                });
                string.pop(); // Pop out the unneeded ' ' character
                if string.is_empty() {
                    return Err(CaseError::NoConditional);
                }
                conditional = Some(string);
            }
            Some(inner) => if argument.is_none() {
                argument = Some(inner);
                continue;
            } else {
                return Err(CaseError::ExtraVar(inner));
            },
            None => (),
        }
        break;
    }

    Ok((argument, binding, conditional))
}

#[cfg(test)]
mod tests {
    use super::parse_case;
    #[test]
    fn case_parsing() {
        assert_eq!(
            Ok((Some("test"), Some("test"), Some("exists".into()))),
            parse_case("test @ test if exists")
        );
        assert_eq!(
            Ok((Some("test"), Some("test"), None)),
            parse_case("test @ test")
        );
        assert_eq!(Ok((Some("test"), None, None)), parse_case("test"));
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::{FileName, SourceFileAndLine};

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let function_span = self.mir.span;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
            // In order to have a good line stepping behavior in debugger, we overwrite debug
            // locations of macro expansions with that of the outermost expansion site
            // (unless the crate is being compiled with `-Z debug-macros`).
            let span = if !span.from_expansion() ||
                tcx.sess.opts.debugging_opts.debug_macros {
                span
            } else {
                // Walk up the macro expansion chain until we reach a non-expanded span.
                // We also stop at the function body level because no line stepping can occur
                // at the level above that.
                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
            };

            let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
                Ok(SourceFileAndLine { sf: file, line }) => {
                    let line_pos = file.line_begin_pos(span.lo());

                    (file, u64::try_from(line).unwrap() + 1, u64::from((span.lo() - line_pos).to_u32()) + 1)
                }
                Err(file) => (file, 0, 0)
            };

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &mut last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &file.name);
                line_program.row().file = file_id;
                last_file = Some(file.clone());
            }

            line_program.row().line = line;
            line_program.row().column = col;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<commit_msg>Don't lookup span position when the span hasn't changed<commit_after>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::{FileName, SourceFileAndLine};

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let function_span = self.mir.span;
        let mut last_span = None;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            if let Some(last_span) = last_span {
                if span == last_span {
                    line_program.generate_row();
                    return;
                }
            }
            last_span = Some(span);

            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
            // In order to have a good line stepping behavior in debugger, we overwrite debug
            // locations of macro expansions with that of the outermost expansion site
            // (unless the crate is being compiled with `-Z debug-macros`).
            let span = if !span.from_expansion() ||
                tcx.sess.opts.debugging_opts.debug_macros {
                span
            } else {
                // Walk up the macro expansion chain until we reach a non-expanded span.
                // We also stop at the function body level because no line stepping can occur
                // at the level above that.
                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
            };

            let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
                Ok(SourceFileAndLine { sf: file, line }) => {
                    let line_pos = file.line_begin_pos(span.lo());

                    (file, u64::try_from(line).unwrap() + 1, u64::from((span.lo() - line_pos).to_u32()) + 1)
                }
                Err(file) => (file, 0, 0)
            };

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &file.name);
                line_program.row().file = file_id;
                last_file = Some(file.clone());
            }

            line_program.row().line = line;
            line_program.row().column = col;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<|endoftext|>