<commit_before>#![feature(test, associated_consts)]
extern crate test;
use test::Bencher;

extern crate hyper;
extern crate webapp_demo;

use hyper::server::Request;
use webapp_demo::host::*;

macro_rules! service {
    ($route:expr => $ident:ident) => (
        struct $ident;
        impl Route for $ident {
            const ROUTE: &'static str = $route;
        }

        impl Get for $ident {
            fn call(&self, _: Params, _: Request) -> HttpFuture {
                unimplemented!()
            }
        }

        impl Post for $ident {
            fn call(&self, _: Params, _: Request) -> HttpFuture {
                unimplemented!()
            }
        }
    )
}

service!("/" => Root);
service!("/a" => A);
service!("/a/b" => B);
service!("/a/b/c" => C);
service!("/a/b/c/d" => D);

#[bench]
fn clone_router_0(b: &mut Bencher) {
    let router = RouterBuilder::new().build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}

#[bench]
fn clone_router_6(b: &mut Bencher) {
    let router = RouterBuilder::new()
        .get(Root)
        .get(A)
        .get(B)
        .post(Root)
        .post(A)
        .post(B)
        .build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}

#[bench]
fn clone_router_10(b: &mut Bencher) {
    let router = RouterBuilder::new()
        .get(Root)
        .get(A)
        .get(B)
        .get(C)
        .get(D)
        .post(Root)
        .post(A)
        .post(B)
        .post(C)
        .post(D)
        .build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}<commit_msg>add quick bench for boxing<commit_after>#![feature(test, associated_consts)]
extern crate test;
use test::Bencher;

extern crate futures;
extern crate hyper;
extern crate webapp_demo;

use hyper::server::{ Request, Response };
use webapp_demo::host::*;

macro_rules! service {
    ($route:expr => $ident:ident) => (
        struct $ident;
        impl Route for $ident {
            const ROUTE: &'static str = $route;
        }

        impl Get for $ident {
            fn call(&self, _: Params, _: Request) -> HttpFuture {
                unimplemented!()
            }
        }

        impl Post for $ident {
            fn call(&self, _: Params, _: Request) -> HttpFuture {
                unimplemented!()
            }
        }
    )
}

service!("/" => Root);
service!("/a" => A);
service!("/a/b" => B);
service!("/a/b/c" => C);
service!("/a/b/c/d" => D);

#[bench]
fn clone_router_0(b: &mut Bencher) {
    let router = RouterBuilder::new().build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}

#[bench]
fn clone_router_6(b: &mut Bencher) {
    let router = RouterBuilder::new()
        .get(Root)
        .get(A)
        .get(B)
        .post(Root)
        .post(A)
        .post(B)
        .build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}

#[bench]
fn clone_router_10(b: &mut Bencher) {
    let router = RouterBuilder::new()
        .get(Root)
        .get(A)
        .get(B)
        .get(C)
        .get(D)
        .post(Root)
        .post(A)
        .post(B)
        .post(C)
        .post(D)
        .build();

    b.iter(|| {
        test::black_box(router.clone())
    })
}

#[bench]
fn box_finished_future(b: &mut Bencher) {
    fn response() -> Box<futures::Finished<Response, ()>> {
        Box::new(futures::finished(Response::new()))
    }

    b.iter(|| {
        test::black_box(response())
    })
}<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_int {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                self
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                self
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                self
            }
        }
    };
}
macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                num_traits::Float::round(self)
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}

num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);
<commit_msg>Add comment explaining euclid's Zero and One traits.<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

// Euclid has its own Zero and One traits instead of of using the num_traits equivalents.
// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things:
//  - Most importantly, for Point2D to implement Zero it would need to implement Add<Self> which we
//    don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow
//    "Point + Point".
//  - Some operations that require, say, One and Div (for example Scale::inv) currently return a
//    type parameterized over T::Output which is ambiguous with num_traits::One because it inherits
//    Mul which also has an Output associated type. To fix it need to complicate type signatures
//    by using <T as Trait>::Output which makes the code and documentation harder to read.
//
// On the other hand, euclid::num::Zero/One are automatically implemented for all types that
// implement their num_traits counterpart. Euclid users never need to explicitly use
// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk
// of compatibility issues with euclid.

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_int {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                self
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                self
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                self
            }
        }
    };
}
macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                num_traits::Float::round(self)
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}

num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);
<|endoftext|>


<commit_before>#![feature(macro_rules)]

macro_rules! return_if_some(
    ($arg:expr) => (
        match $arg {
            Some(val) => return val,
            None => {},
        }
    );
)

pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    use std::str::Chars;
    let pattern_chars = cursor(pattern);
    let mut path_chars = cursor(pathstring);
    return pathmatch_impl(pattern_chars, &mut path_chars, false);

    #[deriving(Clone)]
    struct Cursor<'a>
    {
        chars: Chars<'a>,
        at_the_beginning: bool,
    }

    fn cursor<'a>(arg: &'a str) -> Cursor<'a>
    {
        Cursor { chars: arg.chars(), at_the_beginning: true }
    }

    impl<'a> Iterator<char> for Cursor<'a>
    {
        fn next<'a>(&mut self) -> Option<char>
        {
            self.at_the_beginning = false;
            return self.chars.next();
        }
    }

    fn pathmatch_impl(mut pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        if path_chars.at_the_beginning && char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
            // How can I convert Skip<Cursor> to Cursor to make use of .skip(3) ?
            let mut pattern_chars_copy = pattern_chars;
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                return true;
            }
        }
        loop {
            if char_iter_equals(pattern_chars, "/**", alt_branch_mode, false) && path_chars.peekable().is_empty() {
                return true;
            }
            match pattern_chars.next() {
                None => return path_chars.next().is_none(),
                Some('?') => match path_chars.next() {
                    None | Some('/') => return false,
                    _ => (),
                },
                Some('*') => match pattern_chars.peekable().peek() {
                    Some(&'*') => {
                        pattern_chars.next();
                        return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, true));
                    },
                    _ => return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, false)),
                },
                Some('/') => {
                    return_if_some!(match_exact('/', path_chars.next(), alt_branch_mode));
                    if char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
                        let mut pattern_chars_copy = pattern_chars;
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                            return true;
                        }
                    }
                },
                Some('{') => {
                    let mut matched_something = false;
                    loop {
                        if !matched_something && pathmatch_try(pattern_chars, path_chars, true) {
                            matched_something = true;
                        }
                        match skip_alt_branch(&mut pattern_chars) {
                            Some(false) => break,
                            Some(true) => {},
                            None => /* error in pattern */ return false,
                        }
                    }
                    if !matched_something {
                        return false;
                    }
                },
                Some(',') | Some('}') if alt_branch_mode => return true,
                Some(pc) => return_if_some!(match_exact(pc, path_chars.next(), alt_branch_mode)),
            }
        }
    }

    fn pathmatch_try(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        let mut path_chars_copy = path_chars.clone();
        if pathmatch_impl(pattern_chars, &mut path_chars_copy, alt_branch_mode) {
            *path_chars = path_chars_copy;
            return true;
        }
        return false;
    }

    fn skip_alt_branch(pattern_chars: &mut Cursor) -> Option<bool>
    {
        loop {
            match pattern_chars.next() {
                Some(',') => return Some(true),
                Some('}') => return Some(false),
                Some('{') => if skip_alt_branch(pattern_chars).is_none() { return None; },
                None => return None,
                _ => {},
            }
        }
    }

    fn match_any(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool, allow_pathsep: bool) -> Option<bool>
    {
        loop {
            if pathmatch_try(pattern_chars, path_chars, alt_branch_mode) {
                return Some(true);
            }
            match path_chars.next() {
                None => return None,
                Some('/') if !allow_pathsep => return Some(false),
                _ => {},
            }
        }
    }

    fn match_exact(pattern_char: char, path_char: Option<char>, alt_branch_mode: bool) -> Option<bool>
    {
        match path_char {
            None => return Some(false),
            Some(',') | Some('}') if alt_branch_mode => return Some(false),
            Some(x) if x != pattern_char => return Some(false),
            _ => return None,
        }
    }

    fn char_iter_equals(mut char_iter: Cursor, needle: &str, alt_branch_mode: bool, startswith: bool) -> bool
    {
        for needle_char in needle.chars() {
            match char_iter.next() {
                Some(x) if x == needle_char => (),
                _ => return false,
            }
        }
        if startswith { true }
        else if alt_branch_mode {
            match char_iter.next() {
                Some(',') | Some('}') => true,
                _ => false,
            }
        } else { char_iter.next().is_none() }
    }
}

#[cfg(test)]
fn assert_pathmatch_many(pattern: &str, paths_yes: &[&str], paths_no: &[&str])
{
    for path in paths_yes.iter() {
        assert!(pathmatch(pattern, *path), "should match: pattern:'{}' path:'{}'", pattern, path);
    }
    for path in paths_no.iter() {
        assert!(!pathmatch(pattern, *path), "must not match: pattern:'{}' path:'{}'", pattern, path);
    }
}

#[test]
fn pathmatch_test_alt_combos()
{
    assert_pathmatch_many("a{?,/}c", ["abc", "a/c"], ["ac", "abbc"]);
    assert_pathmatch_many("{foo/**,**/bar}", ["foo", "bar"], ["foobar"]);
    assert_pathmatch_many("{foo/**,bar}baz", ["barbaz", "foo/baz"], ["foobaz"]);
    assert_pathmatch_many("foo{bar,**/baz}", ["foobar", "foo/baz"], ["foobaz"]);
}

#[test]
fn pathmatch_test_alt()
{
    assert!(pathmatch("{foo}", "foo"));
    assert_pathmatch_many("{foo,bar,baz}", ["foo", "bar", "baz"], ["", "foobarbaz", "qux"]);
    assert_pathmatch_many("{foo,bar}", ["foo", "bar"], ["", "foobar"]);
    assert!(pathmatch("{}", ""));
    assert!(!pathmatch("{}", "{}"));
    assert!(pathmatch("{foo}{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "fooXXbar"));
}

#[test]
fn pathmatch_test_collapse()
{
    // `/**/` may match a single slash.
    assert!(pathmatch("foo/**/bar", "foo/bar"));
    assert!(pathmatch("foo/**/", "foo/"));
    assert!(!pathmatch("foo/**/", "foo"));
    assert!(pathmatch("/**/bar", "/bar"));
    assert!(!pathmatch("/**/bar", "bar"));
    // to prevent this behavior, you would use this
    assert!(!pathmatch("foo/*/**/bar", "foo/bar"));
    assert!(!pathmatch("foo/**/*/bar", "foo/bar"));
    assert!(pathmatch("foo/**/bar", "foo//bar"));
    assert!(pathmatch("foo/*/**/bar", "foo//bar"));
}

#[test]
fn pathmatch_test_anypath_leading()
{
    // `**/` at the beginning of pattern may match nothing.
    assert!(pathmatch("**/bar", "bar"));
    assert!(pathmatch("**/bar", "/bar"));
    assert!(!pathmatch("a**/bar", "abar"));
    assert!(!pathmatch("*/bar", "bar"));
}

#[test]
fn pathmatch_test_anypath_trailing()
{
    // `/**` at the end of pattern may match nothing.
    assert!(pathmatch("foo/**", "foo"));
    assert!(pathmatch("foo/**", "foo/"));
    assert!(!pathmatch("foo/**g", "foog"));
    assert!(!pathmatch("foo/*", "foo"));
}

#[test]
fn pathmatch_test_anypath()
{
    assert!(pathmatch("**", ""));
    assert!(pathmatch("a**", "a/b/c"));
    assert!(pathmatch("**c", "a/b/c"));
    assert!(pathmatch("a**c", "a/b/c"));
    assert!(pathmatch("a/**/c", "a/b/c"));
    assert!(pathmatch("**/c", "a/b/c"));
    assert!(!pathmatch("**/g", "e/fg"));
    assert!(pathmatch("a/**", "a/b/c"));
    assert!(!pathmatch("e/**", "ef/g"));
}

#[test]
fn pathmatch_test_pathsep()
{
    assert!(!pathmatch("a?b", "a/b"));
    assert!(!pathmatch("a*b", "a/b"));
    assert!(pathmatch("a*/b", "a/b"));
    assert!(pathmatch("a/*b", "a/b"));
}

#[test]
fn pathmatch_test_anyname()
{
    assert!(pathmatch("*", ""));
    assert!(pathmatch("*", "?"));
    assert!(pathmatch("*", "d?F"));
    assert!(pathmatch("a*", "a"));
    assert!(pathmatch("a*", "abcdef"));
    assert!(pathmatch("*f", "abcdef"));
    assert!(pathmatch("a*f", "abcdef"));
    assert!(pathmatch("*cd*", "abcdef"));
    assert!(pathmatch("a*cd*f", "abcdef"));
    assert!(pathmatch("acdf", "acdf"));
    assert!(!pathmatch("*a", "abc"));
    assert!(!pathmatch("c*", "abc"));
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<commit_msg>disallow **/ and /** to match empty string<commit_after>#![feature(macro_rules)]

macro_rules! return_if_some(
    ($arg:expr) => (
        match $arg {
            Some(val) => return val,
            None => {},
        }
    );
)

pub fn pathmatch(pattern: &str, pathstring: &str) -> bool
{
    use std::str::Chars;
    let pattern_chars = cursor(pattern);
    let mut path_chars = cursor(pathstring);
    return pathmatch_impl(pattern_chars, &mut path_chars, false);

    #[deriving(Clone)]
    struct Cursor<'a>
    {
        chars: Chars<'a>,
        at_the_beginning: bool,
    }

    fn cursor<'a>(arg: &'a str) -> Cursor<'a>
    {
        Cursor { chars: arg.chars(), at_the_beginning: true }
    }

    impl<'a> Iterator<char> for Cursor<'a>
    {
        fn next<'a>(&mut self) -> Option<char>
        {
            self.at_the_beginning = false;
            return self.chars.next();
        }
    }

    fn pathmatch_impl(mut pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        if path_chars.at_the_beginning && char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
            // How can I convert Skip<Cursor> to Cursor to make use of .skip(3) ?
            let mut pattern_chars_copy = pattern_chars;
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            pattern_chars_copy.next();
            if !path_chars.peekable().is_empty() && pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                return true;
            }
        }
        loop {
            if !path_chars.at_the_beginning && char_iter_equals(pattern_chars, "/**", alt_branch_mode, false) && path_chars.peekable().is_empty() {
                return true;
            }
            match pattern_chars.next() {
                None => return path_chars.next().is_none(),
                Some('?') => match path_chars.next() {
                    None | Some('/') => return false,
                    _ => (),
                },
                Some('*') => match pattern_chars.peekable().peek() {
                    Some(&'*') => {
                        pattern_chars.next();
                        return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, true));
                    },
                    _ => return_if_some!(match_any(pattern_chars, path_chars, alt_branch_mode, false)),
                },
                Some('/') => {
                    return_if_some!(match_exact('/', path_chars.next(), alt_branch_mode));
                    if char_iter_equals(pattern_chars, "**/", alt_branch_mode, true) {
                        let mut pattern_chars_copy = pattern_chars;
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        pattern_chars_copy.next();
                        if pathmatch_try(pattern_chars_copy, path_chars, alt_branch_mode) {
                            return true;
                        }
                    }
                },
                Some('{') => {
                    let mut matched_something = false;
                    loop {
                        if !matched_something && pathmatch_try(pattern_chars, path_chars, true) {
                            matched_something = true;
                        }
                        match skip_alt_branch(&mut pattern_chars) {
                            Some(false) => break,
                            Some(true) => {},
                            None => /* error in pattern */ return false,
                        }
                    }
                    if !matched_something {
                        return false;
                    }
                },
                Some(',') | Some('}') if alt_branch_mode => return true,
                Some(pc) => return_if_some!(match_exact(pc, path_chars.next(), alt_branch_mode)),
            }
        }
    }

    fn pathmatch_try(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool) -> bool
    {
        let mut path_chars_copy = path_chars.clone();
        if pathmatch_impl(pattern_chars, &mut path_chars_copy, alt_branch_mode) {
            *path_chars = path_chars_copy;
            return true;
        }
        return false;
    }

    fn skip_alt_branch(pattern_chars: &mut Cursor) -> Option<bool>
    {
        loop {
            match pattern_chars.next() {
                Some(',') => return Some(true),
                Some('}') => return Some(false),
                Some('{') => if skip_alt_branch(pattern_chars).is_none() { return None; },
                None => return None,
                _ => {},
            }
        }
    }

    fn match_any(pattern_chars: Cursor, path_chars: &mut Cursor, alt_branch_mode: bool, allow_pathsep: bool) -> Option<bool>
    {
        loop {
            if pathmatch_try(pattern_chars, path_chars, alt_branch_mode) {
                return Some(true);
            }
            match path_chars.next() {
                None => return None,
                Some('/') if !allow_pathsep => return Some(false),
                _ => {},
            }
        }
    }

    fn match_exact(pattern_char: char, path_char: Option<char>, alt_branch_mode: bool) -> Option<bool>
    {
        match path_char {
            None => return Some(false),
            Some(',') | Some('}') if alt_branch_mode => return Some(false),
            Some(x) if x != pattern_char => return Some(false),
            _ => return None,
        }
    }

    fn char_iter_equals(mut char_iter: Cursor, needle: &str, alt_branch_mode: bool, startswith: bool) -> bool
    {
        for needle_char in needle.chars() {
            match char_iter.next() {
                Some(x) if x == needle_char => (),
                _ => return false,
            }
        }
        if startswith { true }
        else if alt_branch_mode {
            match char_iter.next() {
                Some(',') | Some('}') => true,
                _ => false,
            }
        } else { char_iter.next().is_none() }
    }
}

#[cfg(test)]
fn assert_pathmatch_many(pattern: &str, paths_yes: &[&str], paths_no: &[&str])
{
    for path in paths_yes.iter() {
        assert!(pathmatch(pattern, *path), "should match: pattern:'{}' path:'{}'", pattern, path);
    }
    for path in paths_no.iter() {
        assert!(!pathmatch(pattern, *path), "must not match: pattern:'{}' path:'{}'", pattern, path);
    }
}

#[test]
fn pathmatch_test_alt_combos()
{
    assert_pathmatch_many("a{?,/}c", ["abc", "a/c"], ["ac", "abbc"]);
    assert_pathmatch_many("{foo/**,**/bar}", ["foo", "bar"], ["foobar"]);
    assert_pathmatch_many("{foo/**,bar}baz", ["barbaz", "foo/baz"], ["foobaz"]);
    assert_pathmatch_many("foo{bar,**/baz}", ["foobar", "foo/baz"], ["foobaz"]);
    assert!(!pathmatch("{**/}", ""));
    assert!(!pathmatch("{{**/}}", ""));
}

#[test]
fn pathmatch_test_alt()
{
    assert!(pathmatch("{foo}", "foo"));
    assert_pathmatch_many("{foo,bar,baz}", ["foo", "bar", "baz"], ["", "foobarbaz", "qux"]);
    assert_pathmatch_many("{foo,bar}", ["foo", "bar"], ["", "foobar"]);
    assert!(pathmatch("{}", ""));
    assert!(!pathmatch("{}", "{}"));
    assert!(pathmatch("{foo}{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "foobar"));
    assert!(pathmatch("{foo}*{bar}", "fooXXbar"));
}

#[test]
fn pathmatch_test_collapse()
{
    // `/**/` may match a single slash.
    assert!(pathmatch("foo/**/bar", "foo/bar"));
    assert!(pathmatch("foo/**/", "foo/"));
    assert!(!pathmatch("foo/**/", "foo"));
    assert!(pathmatch("/**/bar", "/bar"));
    assert!(!pathmatch("/**/bar", "bar"));
    // to prevent this behavior, you would use this
    assert!(!pathmatch("foo/*/**/bar", "foo/bar"));
    assert!(!pathmatch("foo/**/*/bar", "foo/bar"));
    assert!(pathmatch("foo/**/bar", "foo//bar"));
    assert!(pathmatch("foo/*/**/bar", "foo//bar"));
}

#[test]
fn pathmatch_test_anypath_leading()
{
    // `**/` at the beginning of pattern may match nothing.
    assert!(pathmatch("**/bar", "bar"));
    assert!(pathmatch("**/bar", "/bar"));
    assert!(!pathmatch("a**/bar", "abar"));
    assert!(!pathmatch("*/bar", "bar"));
    assert!(!pathmatch("**/", ""));
}

#[test]
fn pathmatch_test_anypath_trailing()
{
    // `/**` at the end of pattern may match nothing.
    assert!(pathmatch("foo/**", "foo"));
    assert!(pathmatch("foo/**", "foo/"));
    assert!(!pathmatch("foo/**g", "foog"));
    assert!(!pathmatch("foo/*", "foo"));
    assert!(!pathmatch("/**", ""));
    assert!(pathmatch("/**", "/"));
}

#[test]
fn pathmatch_test_anypath()
{
    assert!(pathmatch("**", ""));
    assert!(pathmatch("a**", "a/b/c"));
    assert!(pathmatch("**c", "a/b/c"));
    assert!(pathmatch("a**c", "a/b/c"));
    assert!(pathmatch("a/**/c", "a/b/c"));
    assert!(pathmatch("**/c", "a/b/c"));
    assert!(!pathmatch("**/g", "e/fg"));
    assert!(pathmatch("a/**", "a/b/c"));
    assert!(!pathmatch("e/**", "ef/g"));
}

#[test]
fn pathmatch_test_pathsep()
{
    assert!(!pathmatch("a?b", "a/b"));
    assert!(!pathmatch("a*b", "a/b"));
    assert!(pathmatch("a*/b", "a/b"));
    assert!(pathmatch("a/*b", "a/b"));
}

#[test]
fn pathmatch_test_anyname()
{
    assert!(pathmatch("*", ""));
    assert!(pathmatch("*", "?"));
    assert!(pathmatch("*", "d?F"));
    assert!(pathmatch("a*", "a"));
    assert!(pathmatch("a*", "abcdef"));
    assert!(pathmatch("*f", "abcdef"));
    assert!(pathmatch("a*f", "abcdef"));
    assert!(pathmatch("*cd*", "abcdef"));
    assert!(pathmatch("a*cd*f", "abcdef"));
    assert!(pathmatch("acdf", "acdf"));
    assert!(!pathmatch("*a", "abc"));
    assert!(!pathmatch("c*", "abc"));
}

#[test]
fn pathmatch_test_anychar()
{
    assert!(pathmatch("?", "?"));
    assert!(pathmatch("?", "a"));
    assert!(pathmatch("??", "BC"));
    assert!(pathmatch("B?", "BC"));
    assert!(pathmatch("?C", "BC"));
    assert!(!pathmatch("?", ""));
    assert!(!pathmatch("D?", "BC"));
    assert!(!pathmatch("?E", "BC"));
}

#[test]
fn pathmatch_test_exact_equality()
{
    assert!(pathmatch("", ""));
    assert!(pathmatch("a", "a"));
    assert!(pathmatch("BC", "BC"));
    assert!(!pathmatch("a", ""));
    assert!(!pathmatch("", "BC"));
}

<|endoftext|>


<commit_before>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all("HB    Tag    \
              Global_Work    Window_Work    Work    \
              Global_Time    Window_Time    Start_Time    End_Time    \
              Global_Perf    Window_Perf    Instant_Perf    \
              Global_Energy    Window_Energy    Start_Energy    End_Energy    \
              Global_Pwr    Window_Pwr    Instant_Pwr\n".as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{}    {}    \
                         {}    {}    {}    \
                         {}    {}    {}    {}    \
                         {}    {}    {}    \
                         {}    {}    {}    {}    \
                         {}    {}    {}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<commit_msg>format log output<commit_after>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all(format!("{:6} {:6} \
                         {:11} {:11} {:11} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {:15} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {}\n",
                        "HB", "Tag",
                        "Global_Work", "Window_Work", "Work",
                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
                        "Global_Perf", "Window_Perf", "Instant_Perf",
                        "Global_Energy", "Window_Energy", "Start_Energy", "End_Energy",
                        "Global_Pwr", "Window_Pwr", "Instant_Pwr").as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{:<6} {:<6} \
                         {:<11} {:<11} {:<11} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<15.6} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<.6}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<|endoftext|>


<commit_before>//! Contains basic data about various HIR declarations.

use std::sync::Arc;

use hir_expand::{name::Name, InFile};
use syntax::ast;

use crate::{
    attr::Attrs,
    body::Expander,
    db::DefDatabase,
    intern::Interned,
    item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param},
    type_ref::{TraitRef, TypeBound, TypeRef},
    visibility::RawVisibility,
    AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
    Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
    pub name: Name,
    pub params: Vec<Interned<TypeRef>>,
    pub ret_type: Interned<TypeRef>,
    pub async_ret_type: Option<Interned<TypeRef>>,
    pub attrs: Attrs,
    pub visibility: RawVisibility,
    pub abi: Option<Interned<str>>,
    flags: FnFlags,
}

impl FunctionData {
    pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
        let loc = func.lookup(db);
        let krate = loc.container.module(db).krate;
        let crate_graph = db.crate_graph();
        let cfg_options = &crate_graph[krate].cfg_options;
        let item_tree = loc.id.item_tree(db);
        let func = &item_tree[loc.id.value];

        let enabled_params = func
            .params
            .clone()
            .filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));

        // If last cfg-enabled param is a `...` param, it's a varargs function.
        let is_varargs = enabled_params
            .clone()
            .next_back()
            .map_or(false, |param| matches!(item_tree[param], Param::Varargs));

        let mut flags = func.flags;
        if is_varargs {
            flags.bits |= FnFlags::IS_VARARGS;
        }

        Arc::new(FunctionData {
            name: func.name.clone(),
            params: enabled_params
                .clone()
                .filter_map(|id| match &item_tree[id] {
                    Param::Normal(ty) => Some(ty.clone()),
                    Param::Varargs => None,
                })
                .collect(),
            ret_type: func.ret_type.clone(),
            async_ret_type: func.async_ret_type.clone(),
            attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
            visibility: item_tree[func.visibility].clone(),
            abi: func.abi.clone(),
            flags,
        })
    }

    pub fn has_body(&self) -> bool {
        self.flags.bits & FnFlags::HAS_BODY != 0
    }

    /// True if the first param is `self`. This is relevant to decide whether this
    /// can be called as a method.
    pub fn has_self_param(&self) -> bool {
        self.flags.bits & FnFlags::HAS_SELF_PARAM != 0
    }

    pub fn is_default(&self) -> bool {
        self.flags.bits & FnFlags::IS_DEFAULT != 0
    }

    pub fn is_const(&self) -> bool {
        self.flags.bits & FnFlags::IS_CONST != 0
    }

    pub fn is_async(&self) -> bool {
        self.flags.bits & FnFlags::IS_ASYNC != 0
    }

    pub fn is_unsafe(&self) -> bool {
        self.flags.bits & FnFlags::IS_UNSAFE != 0
    }

    pub fn is_in_extern_block(&self) -> bool {
        self.flags.bits & FnFlags::IS_IN_EXTERN_BLOCK != 0
    }

    pub fn is_varargs(&self) -> bool {
        self.flags.bits & FnFlags::IS_VARARGS != 0
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
    pub name: Name,
    pub type_ref: Option<Interned<TypeRef>>,
    pub visibility: RawVisibility,
    pub is_extern: bool,
    /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
    pub bounds: Vec<Interned<TypeBound>>,
}

impl TypeAliasData {
    pub(crate) fn type_alias_data_query(
        db: &dyn DefDatabase,
        typ: TypeAliasId,
    ) -> Arc<TypeAliasData> {
        let loc = typ.lookup(db);
        let item_tree = loc.id.item_tree(db);
        let typ = &item_tree[loc.id.value];

        Arc::new(TypeAliasData {
            name: typ.name.clone(),
            type_ref: typ.type_ref.clone(),
            visibility: item_tree[typ.visibility].clone(),
            is_extern: typ.is_extern,
            bounds: typ.bounds.to_vec(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
    pub name: Name,
    pub items: Vec<(Name, AssocItemId)>,
    pub is_auto: bool,
    pub is_unsafe: bool,
    pub visibility: RawVisibility,
    pub skip_array_during_method_dispatch: bool,
}

impl TraitData {
    pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
        let tr_loc = tr.lookup(db);
        let item_tree = tr_loc.id.item_tree(db);
        let tr_def = &item_tree[tr_loc.id.value];
        let name = tr_def.name.clone();
        let is_auto = tr_def.is_auto;
        let is_unsafe = tr_def.is_unsafe;
        let module_id = tr_loc.container;
        let container = AssocContainerId::TraitId(tr);
        let visibility = item_tree[tr_def.visibility].clone();
        let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
        let skip_array_during_method_dispatch = item_tree
            .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
            .by_key("rustc_skip_array_during_method_dispatch")
            .exists();

        let items = collect_items(
            db,
            module_id,
            &mut expander,
            tr_def.items.iter().copied(),
            tr_loc.id.file_id(),
            container,
            100,
        );

        Arc::new(TraitData {
            name,
            items,
            is_auto,
            is_unsafe,
            visibility,
            skip_array_during_method_dispatch,
        })
    }

    pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
        self.items.iter().filter_map(|(_name, item)| match item {
            AssocItemId::TypeAliasId(t) => Some(*t),
            _ => None,
        })
    }

    pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
        self.items.iter().find_map(|(item_name, item)| match item {
            AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
            _ => None,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplData {
    pub target_trait: Option<Interned<TraitRef>>,
    pub self_ty: Interned<TypeRef>,
    pub items: Vec<AssocItemId>,
    pub is_negative: bool,
}

impl ImplData {
    pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
        let _p = profile::span("impl_data_query");
        let impl_loc = id.lookup(db);

        let item_tree = impl_loc.id.item_tree(db);
        let impl_def = &item_tree[impl_loc.id.value];
        let target_trait = impl_def.target_trait.clone();
        let self_ty = impl_def.self_ty.clone();
        let is_negative = impl_def.is_negative;
        let module_id = impl_loc.container;
        let container = AssocContainerId::ImplId(id);
        let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);

        let items = collect_items(
            db,
            module_id,
            &mut expander,
            impl_def.items.iter().copied(),
            impl_loc.id.file_id(),
            container,
            100,
        );
        let items = items.into_iter().map(|(_, item)| item).collect();

        Arc::new(ImplData { target_trait, self_ty, items, is_negative })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstData {
    /// const _: () = ();
    pub name: Option<Name>,
    pub type_ref: Interned<TypeRef>,
    pub visibility: RawVisibility,
}

impl ConstData {
    pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
        let loc = konst.lookup(db);
        let item_tree = loc.id.item_tree(db);
        let konst = &item_tree[loc.id.value];

        Arc::new(ConstData {
            name: konst.name.clone(),
            type_ref: konst.type_ref.clone(),
            visibility: item_tree[konst.visibility].clone(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData {
    pub name: Option<Name>,
    pub type_ref: Interned<TypeRef>,
    pub visibility: RawVisibility,
    pub mutable: bool,
    pub is_extern: bool,
}

impl StaticData {
    pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
        let node = konst.lookup(db);
        let item_tree = node.id.item_tree(db);
        let statik = &item_tree[node.id.value];

        Arc::new(StaticData {
            name: Some(statik.name.clone()),
            type_ref: statik.type_ref.clone(),
            visibility: item_tree[statik.visibility].clone(),
            mutable: statik.mutable,
            is_extern: statik.is_extern,
        })
    }
}

fn collect_items(
    db: &dyn DefDatabase,
    module: ModuleId,
    expander: &mut Expander,
    assoc_items: impl Iterator<Item = AssocItem>,
    file_id: crate::HirFileId,
    container: AssocContainerId,
    limit: usize,
) -> Vec<(Name, AssocItemId)> {
    if limit == 0 {
        return Vec::new();
    }

    let item_tree = db.file_item_tree(file_id);
    let crate_graph = db.crate_graph();
    let cfg_options = &crate_graph[module.krate].cfg_options;

    let mut items = Vec::new();
    for item in assoc_items {
        let attrs = item_tree.attrs(db, module.krate, ModItem::from(item).into());
        if !attrs.is_cfg_enabled(cfg_options) {
            continue;
        }

        match item {
            AssocItem::Function(id) => {
                let item = &item_tree[id];
                let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((item.name.clone(), def.into()));
            }
            AssocItem::Const(id) => {
                let item = &item_tree[id];
                let name = match item.name.clone() {
                    Some(name) => name,
                    None => continue,
                };
                let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((name, def.into()));
            }
            AssocItem::TypeAlias(id) => {
                let item = &item_tree[id];
                let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((item.name.clone(), def.into()));
            }
            AssocItem::MacroCall(call) => {
                let call = &item_tree[call];
                let ast_id_map = db.ast_id_map(file_id);
                let root = db.parse_or_expand(file_id).unwrap();
                let call = ast_id_map.get(call.ast_id).to_node(&root);
                let res = expander.enter_expand(db, call);

                if let Ok(res) = res {
                    if let Some((mark, mac)) = res.value {
                        let src: InFile<ast::MacroItems> = expander.to_source(mac);
                        let item_tree = db.file_item_tree(src.file_id);
                        let iter =
                            item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
                        items.extend(collect_items(
                            db,
                            module,
                            expander,
                            iter,
                            src.file_id,
                            container,
                            limit - 1,
                        ));

                        expander.exit(db, mark);
                    }
                }
            }
        }
    }

    items
}
<commit_msg>Add comment<commit_after>//! Contains basic data about various HIR declarations.

use std::sync::Arc;

use hir_expand::{name::Name, InFile};
use syntax::ast;

use crate::{
    attr::Attrs,
    body::Expander,
    db::DefDatabase,
    intern::Interned,
    item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param},
    type_ref::{TraitRef, TypeBound, TypeRef},
    visibility::RawVisibility,
    AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
    Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
    pub name: Name,
    pub params: Vec<Interned<TypeRef>>,
    pub ret_type: Interned<TypeRef>,
    pub async_ret_type: Option<Interned<TypeRef>>,
    pub attrs: Attrs,
    pub visibility: RawVisibility,
    pub abi: Option<Interned<str>>,
    flags: FnFlags,
}

impl FunctionData {
    pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
        let loc = func.lookup(db);
        let krate = loc.container.module(db).krate;
        let crate_graph = db.crate_graph();
        let cfg_options = &crate_graph[krate].cfg_options;
        let item_tree = loc.id.item_tree(db);
        let func = &item_tree[loc.id.value];

        let enabled_params = func
            .params
            .clone()
            .filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));

        // If last cfg-enabled param is a `...` param, it's a varargs function.
        let is_varargs = enabled_params
            .clone()
            .next_back()
            .map_or(false, |param| matches!(item_tree[param], Param::Varargs));

        let mut flags = func.flags;
        if is_varargs {
            flags.bits |= FnFlags::IS_VARARGS;
        }

        Arc::new(FunctionData {
            name: func.name.clone(),
            params: enabled_params
                .clone()
                .filter_map(|id| match &item_tree[id] {
                    Param::Normal(ty) => Some(ty.clone()),
                    Param::Varargs => None,
                })
                .collect(),
            ret_type: func.ret_type.clone(),
            async_ret_type: func.async_ret_type.clone(),
            attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
            visibility: item_tree[func.visibility].clone(),
            abi: func.abi.clone(),
            flags,
        })
    }

    pub fn has_body(&self) -> bool {
        self.flags.bits & FnFlags::HAS_BODY != 0
    }

    /// True if the first param is `self`. This is relevant to decide whether this
    /// can be called as a method.
    pub fn has_self_param(&self) -> bool {
        self.flags.bits & FnFlags::HAS_SELF_PARAM != 0
    }

    pub fn is_default(&self) -> bool {
        self.flags.bits & FnFlags::IS_DEFAULT != 0
    }

    pub fn is_const(&self) -> bool {
        self.flags.bits & FnFlags::IS_CONST != 0
    }

    pub fn is_async(&self) -> bool {
        self.flags.bits & FnFlags::IS_ASYNC != 0
    }

    pub fn is_unsafe(&self) -> bool {
        self.flags.bits & FnFlags::IS_UNSAFE != 0
    }

    pub fn is_in_extern_block(&self) -> bool {
        self.flags.bits & FnFlags::IS_IN_EXTERN_BLOCK != 0
    }

    pub fn is_varargs(&self) -> bool {
        self.flags.bits & FnFlags::IS_VARARGS != 0
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
    pub name: Name,
    pub type_ref: Option<Interned<TypeRef>>,
    pub visibility: RawVisibility,
    pub is_extern: bool,
    /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
    pub bounds: Vec<Interned<TypeBound>>,
}

impl TypeAliasData {
    pub(crate) fn type_alias_data_query(
        db: &dyn DefDatabase,
        typ: TypeAliasId,
    ) -> Arc<TypeAliasData> {
        let loc = typ.lookup(db);
        let item_tree = loc.id.item_tree(db);
        let typ = &item_tree[loc.id.value];

        Arc::new(TypeAliasData {
            name: typ.name.clone(),
            type_ref: typ.type_ref.clone(),
            visibility: item_tree[typ.visibility].clone(),
            is_extern: typ.is_extern,
            bounds: typ.bounds.to_vec(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
    pub name: Name,
    pub items: Vec<(Name, AssocItemId)>,
    pub is_auto: bool,
    pub is_unsafe: bool,
    pub visibility: RawVisibility,
    /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
    /// method calls to this trait's methods when the receiver is an array and the crate edition is
    /// 2015 or 2018.
    pub skip_array_during_method_dispatch: bool,
}

impl TraitData {
    pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
        let tr_loc = tr.lookup(db);
        let item_tree = tr_loc.id.item_tree(db);
        let tr_def = &item_tree[tr_loc.id.value];
        let name = tr_def.name.clone();
        let is_auto = tr_def.is_auto;
        let is_unsafe = tr_def.is_unsafe;
        let module_id = tr_loc.container;
        let container = AssocContainerId::TraitId(tr);
        let visibility = item_tree[tr_def.visibility].clone();
        let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
        let skip_array_during_method_dispatch = item_tree
            .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
            .by_key("rustc_skip_array_during_method_dispatch")
            .exists();

        let items = collect_items(
            db,
            module_id,
            &mut expander,
            tr_def.items.iter().copied(),
            tr_loc.id.file_id(),
            container,
            100,
        );

        Arc::new(TraitData {
            name,
            items,
            is_auto,
            is_unsafe,
            visibility,
            skip_array_during_method_dispatch,
        })
    }

    pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
        self.items.iter().filter_map(|(_name, item)| match item {
            AssocItemId::TypeAliasId(t) => Some(*t),
            _ => None,
        })
    }

    pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
        self.items.iter().find_map(|(item_name, item)| match item {
            AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
            _ => None,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplData {
    pub target_trait: Option<Interned<TraitRef>>,
    pub self_ty: Interned<TypeRef>,
    pub items: Vec<AssocItemId>,
    pub is_negative: bool,
}

impl ImplData {
    pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
        let _p = profile::span("impl_data_query");
        let impl_loc = id.lookup(db);

        let item_tree = impl_loc.id.item_tree(db);
        let impl_def = &item_tree[impl_loc.id.value];
        let target_trait = impl_def.target_trait.clone();
        let self_ty = impl_def.self_ty.clone();
        let is_negative = impl_def.is_negative;
        let module_id = impl_loc.container;
        let container = AssocContainerId::ImplId(id);
        let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);

        let items = collect_items(
            db,
            module_id,
            &mut expander,
            impl_def.items.iter().copied(),
            impl_loc.id.file_id(),
            container,
            100,
        );
        let items = items.into_iter().map(|(_, item)| item).collect();

        Arc::new(ImplData { target_trait, self_ty, items, is_negative })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstData {
    /// const _: () = ();
    pub name: Option<Name>,
    pub type_ref: Interned<TypeRef>,
    pub visibility: RawVisibility,
}

impl ConstData {
    pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
        let loc = konst.lookup(db);
        let item_tree = loc.id.item_tree(db);
        let konst = &item_tree[loc.id.value];

        Arc::new(ConstData {
            name: konst.name.clone(),
            type_ref: konst.type_ref.clone(),
            visibility: item_tree[konst.visibility].clone(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData {
    pub name: Option<Name>,
    pub type_ref: Interned<TypeRef>,
    pub visibility: RawVisibility,
    pub mutable: bool,
    pub is_extern: bool,
}

impl StaticData {
    pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
        let node = konst.lookup(db);
        let item_tree = node.id.item_tree(db);
        let statik = &item_tree[node.id.value];

        Arc::new(StaticData {
            name: Some(statik.name.clone()),
            type_ref: statik.type_ref.clone(),
            visibility: item_tree[statik.visibility].clone(),
            mutable: statik.mutable,
            is_extern: statik.is_extern,
        })
    }
}

fn collect_items(
    db: &dyn DefDatabase,
    module: ModuleId,
    expander: &mut Expander,
    assoc_items: impl Iterator<Item = AssocItem>,
    file_id: crate::HirFileId,
    container: AssocContainerId,
    limit: usize,
) -> Vec<(Name, AssocItemId)> {
    if limit == 0 {
        return Vec::new();
    }

    let item_tree = db.file_item_tree(file_id);
    let crate_graph = db.crate_graph();
    let cfg_options = &crate_graph[module.krate].cfg_options;

    let mut items = Vec::new();
    for item in assoc_items {
        let attrs = item_tree.attrs(db, module.krate, ModItem::from(item).into());
        if !attrs.is_cfg_enabled(cfg_options) {
            continue;
        }

        match item {
            AssocItem::Function(id) => {
                let item = &item_tree[id];
                let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((item.name.clone(), def.into()));
            }
            AssocItem::Const(id) => {
                let item = &item_tree[id];
                let name = match item.name.clone() {
                    Some(name) => name,
                    None => continue,
                };
                let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((name, def.into()));
            }
            AssocItem::TypeAlias(id) => {
                let item = &item_tree[id];
                let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                items.push((item.name.clone(), def.into()));
            }
            AssocItem::MacroCall(call) => {
                let call = &item_tree[call];
                let ast_id_map = db.ast_id_map(file_id);
                let root = db.parse_or_expand(file_id).unwrap();
                let call = ast_id_map.get(call.ast_id).to_node(&root);
                let res = expander.enter_expand(db, call);

                if let Ok(res) = res {
                    if let Some((mark, mac)) = res.value {
                        let src: InFile<ast::MacroItems> = expander.to_source(mac);
                        let item_tree = db.file_item_tree(src.file_id);
                        let iter =
                            item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
                        items.extend(collect_items(
                            db,
                            module,
                            expander,
                            iter,
                            src.file_id,
                            container,
                            limit - 1,
                        ));

                        expander.exit(db, mark);
                    }
                }
            }
        }
    }

    items
}
<|endoftext|>


<commit_before>//! Abstract-ish representation of paths for VFS.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// Path in [`Vfs`].
///
/// Long-term, we want to support files which do not reside in the file-system,
/// so we treat `VfsPath`s as opaque identifiers.
///
/// [`Vfs`]: crate::Vfs
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct VfsPath(VfsPathRepr);

impl VfsPath {
    /// Creates an "in-memory" path from `/`-separated string.
    ///
    /// This is most useful for testing, to avoid windows/linux differences
    ///
    /// # Panics
    ///
    /// Panics if `path` does not start with `'/'`.
    pub fn new_virtual_path(path: String) -> VfsPath {
        assert!(path.starts_with('/'));
        VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path)))
    }

    /// Returns the `AbsPath` representation of `self` if `self` is on the file system.
    pub fn as_path(&self) -> Option<&AbsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => Some(it.as_path()),
            VfsPathRepr::VirtualPath(_) => None,
        }
    }

    /// Creates a new `VfsPath` with `path` adjoined to `self`.
    pub fn join(&self, path: &str) -> Option<VfsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => {
                let res = it.join(path).normalize();
                Some(VfsPath(VfsPathRepr::PathBuf(res)))
            }
            VfsPathRepr::VirtualPath(it) => {
                let res = it.join(path)?;
                Some(VfsPath(VfsPathRepr::VirtualPath(res)))
            }
        }
    }

    /// Remove the last component of `self` if there is one.
    ///
    /// If `self` has no component, returns `false`; else returns `true`.
    ///
    /// # Example
    ///
    /// ```
    /// # use vfs::{AbsPathBuf, VfsPath};
    /// let mut path = VfsPath::from(AbsPathBuf::assert("/foo/bar".into()));
    /// assert!(path.pop());
    /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/foo".into())));
    /// assert!(path.pop());
    /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/".into())));
    /// assert!(!path.pop());
    /// ```
    pub fn pop(&mut self) -> bool {
        match &mut self.0 {
            VfsPathRepr::PathBuf(it) => it.pop(),
            VfsPathRepr::VirtualPath(it) => it.pop(),
        }
    }

    /// Returns `true` if `other` is a prefix of `self`.
    pub fn starts_with(&self, other: &VfsPath) -> bool {
        match (&self.0, &other.0) {
            (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::PathBuf(_), _) => false,
            (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::VirtualPath(_), _) => false,
        }
    }

    /// Returns the `VfsPath` without its final component, if there is one.
    ///
    /// Returns [`None`] if the path is a root or prefix.
    pub fn parent(&self) -> Option<VfsPath> {
        let mut parent = self.clone();
        if parent.pop() {
            Some(parent)
        } else {
            None
        }
    }

    /// Returns `self`'s base name and file extension.
    pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        match &self.0 {
            VfsPathRepr::PathBuf(p) => Some((
                p.file_stem()?.to_str()?,
                p.extension().and_then(|extension| extension.to_str()),
            )),
            VfsPathRepr::VirtualPath(p) => p.name_and_extension(),
        }
    }

    /// **Don't make this `pub`**
    ///
    /// Encode the path in the given buffer.
    ///
    /// The encoding will be `0` if [`AbsPathBuf`], `1` if [`VirtualPath`], followed
    /// by `self`'s representation.
    ///
    /// Note that this encoding is dependent on the operating system.
    pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
        let tag = match &self.0 {
            VfsPathRepr::PathBuf(_) => 0,
            VfsPathRepr::VirtualPath(_) => 1,
        };
        buf.push(tag);
        match &self.0 {
            VfsPathRepr::PathBuf(path) => {
                #[cfg(windows)]
                {
                    use windows_paths::Encode;
                    let path: &std::path::Path = path.as_ref();
                    let components = path.components();
                    let mut add_sep = false;
                    for component in components {
                        if add_sep {
                            windows_paths::SEP.encode(buf);
                        }
                        let len_before = buf.len();
                        match component {
                            std::path::Component::Prefix(prefix) => {
                                // kind() returns a normalized and comparable path prefix.
                                prefix.kind().encode(buf);
                            }
                            std::path::Component::RootDir => {
                                if !add_sep {
                                    component.as_os_str().encode(buf);
                                }
                            }
                            _ => component.as_os_str().encode(buf),
                        }

                        // some components may be encoded empty
                        add_sep = len_before != buf.len();
                    }
                }
                #[cfg(unix)]
                {
                    use std::os::unix::ffi::OsStrExt;
                    buf.extend(path.as_os_str().as_bytes());
                }
                #[cfg(not(any(windows, unix)))]
                {
                    buf.extend(path.as_os_str().to_string_lossy().as_bytes());
                }
            }
            VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()),
        }
    }
}

#[cfg(windows)]
mod windows_paths {
    pub(crate) trait Encode {
        fn encode(&self, buf: &mut Vec<u8>);
    }

    impl Encode for std::ffi::OsStr {
        fn encode(&self, buf: &mut Vec<u8>) {
            use std::os::windows::ffi::OsStrExt;
            for wchar in self.encode_wide() {
                buf.extend(wchar.to_le_bytes().iter().copied());
            }
        }
    }

    impl Encode for u8 {
        fn encode(&self, buf: &mut Vec<u8>) {
            let wide = *self as u16;
            buf.extend(wide.to_le_bytes().iter().copied())
        }
    }

    impl Encode for &str {
        fn encode(&self, buf: &mut Vec<u8>) {
            debug_assert!(self.is_ascii());
            for b in self.as_bytes() {
                b.encode(buf)
            }
        }
    }

    pub(crate) const SEP: &str = "\\";
    const VERBATIM: &str = "\\\\?\\";
    const UNC: &str = "UNC";
    const DEVICE: &str = "\\\\.\\";
    const COLON: &str = ":";

    impl Encode for std::path::Prefix<'_> {
        fn encode(&self, buf: &mut Vec<u8>) {
            match self {
                std::path::Prefix::Verbatim(c) => {
                    VERBATIM.encode(buf);
                    c.encode(buf);
                }
                std::path::Prefix::VerbatimUNC(server, share) => {
                    VERBATIM.encode(buf);
                    UNC.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::VerbatimDisk(d) => {
                    VERBATIM.encode(buf);
                    d.encode(buf);
                    COLON.encode(buf);
                }
                std::path::Prefix::DeviceNS(device) => {
                    DEVICE.encode(buf);
                    device.encode(buf);
                }
                std::path::Prefix::UNC(server, share) => {
                    SEP.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::Disk(d) => {
                    d.encode(buf);
                    COLON.encode(buf);
                }
            }
        }
    }
    #[test]
    fn paths_encoding() {
        // drive letter casing agnostic
        test_eq("C:/x.rs", "c:/x.rs");
        // separator agnostic
        test_eq("C:/x/y.rs", "C:\\x\\y.rs");

        fn test_eq(a: &str, b: &str) {
            let mut b1 = Vec::new();
            let mut b2 = Vec::new();
            vfs(a).encode(&mut b1);
            vfs(b).encode(&mut b2);
            assert_eq!(b1, b2);
        }
    }

    #[test]
    fn test_sep_root_dir_encoding() {
        let mut buf = Vec::new();
        vfs("C:/x/y").encode(&mut buf);
        assert_eq!(&buf, &[0, 67, 0, 58, 0, 92, 0, 120, 0, 92, 0, 121, 0])
    }

    #[cfg(test)]
    fn vfs(str: &str) -> super::VfsPath {
        use super::{AbsPathBuf, VfsPath};
        use std::convert::TryFrom;
        VfsPath::from(AbsPathBuf::try_from(str).unwrap())
    }
}

/// Internal, private representation of [`VfsPath`].
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
enum VfsPathRepr {
    PathBuf(AbsPathBuf),
    VirtualPath(VirtualPath),
}

impl From<AbsPathBuf> for VfsPath {
    fn from(v: AbsPathBuf) -> Self {
        VfsPath(VfsPathRepr::PathBuf(v.normalize()))
    }
}

impl fmt::Display for VfsPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f),
        }
    }
}

impl fmt::Debug for VfsPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Debug for VfsPathRepr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self {
            VfsPathRepr::PathBuf(it) => fmt::Debug::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Debug::fmt(&it, f),
        }
    }
}

/// `/`-separated virtual path.
///
/// This is used to describe files that do not reside on the file system.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
struct VirtualPath(String);

impl VirtualPath {
    /// Returns `true` if `other` is a prefix of `self` (as strings).
    fn starts_with(&self, other: &VirtualPath) -> bool {
        self.0.starts_with(&other.0)
    }

    /// Remove the last component of `self`.
    ///
    /// This will find the last `'/'` in `self`, and remove everything after it,
    /// including the `'/'`.
    ///
    /// If `self` contains no `'/'`, returns `false`; else returns `true`.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut path = VirtualPath("/foo/bar".to_string());
    /// path.pop();
    /// assert_eq!(path.0, "/foo");
    /// path.pop();
    /// assert_eq!(path.0, "");
    /// ```
    fn pop(&mut self) -> bool {
        let pos = match self.0.rfind('/') {
            Some(pos) => pos,
            None => return false,
        };
        self.0 = self.0[..pos].to_string();
        true
    }

    /// Append the given *relative* path `path` to `self`.
    ///
    /// This will resolve any leading `"../"` in `path` before appending it.
    ///
    /// Returns [`None`] if `path` has more leading `"../"` than the number of
    /// components in `self`.
    ///
    /// # Notes
    ///
    /// In practice, appending here means `self/path` as strings.
    fn join(&self, mut path: &str) -> Option<VirtualPath> {
        let mut res = self.clone();
        while path.starts_with("../") {
            if !res.pop() {
                return None;
            }
            path = &path["../".len()..]
        }
        while path.starts_with("./") {
            path = &path["./".len()..]
        }
        res.0 = format!("{}/{}", res.0, path);
        Some(res)
    }

    /// Returns `self`'s base name and file extension.
    ///
    /// # Returns
    /// - `None` if `self` ends with `"//"`.
    /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at
    /// the start.
    /// - `Some((name, Some(extension))` else.
    ///
    /// # Note
    /// The extension will not contains `.`. This means `"/foo/bar.baz.rs"` will
    /// return `Some(("bar.baz", Some("rs"))`.
    fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 };
        let file_name = match file_path.rfind('/') {
            Some(position) => &file_path[position + 1..],
            None => file_path,
        };

        if file_name.is_empty() {
            None
        } else {
            let mut file_stem_and_extension = file_name.rsplitn(2, '.');
            let extension = file_stem_and_extension.next();
            let file_stem = file_stem_and_extension.next();

            match (file_stem, extension) {
                (None, None) => None,
                (None | Some(""), Some(_)) => Some((file_name, None)),
                (Some(file_stem), extension) => Some((file_stem, extension)),
            }
        }
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Update crates/vfs/src/vfs_path.rs<commit_after>//! Abstract-ish representation of paths for VFS.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// Path in [`Vfs`].
///
/// Long-term, we want to support files which do not reside in the file-system,
/// so we treat `VfsPath`s as opaque identifiers.
///
/// [`Vfs`]: crate::Vfs
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct VfsPath(VfsPathRepr);

impl VfsPath {
    /// Creates an "in-memory" path from `/`-separated string.
    ///
    /// This is most useful for testing, to avoid windows/linux differences
    ///
    /// # Panics
    ///
    /// Panics if `path` does not start with `'/'`.
    pub fn new_virtual_path(path: String) -> VfsPath {
        assert!(path.starts_with('/'));
        VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path)))
    }

    /// Returns the `AbsPath` representation of `self` if `self` is on the file system.
    pub fn as_path(&self) -> Option<&AbsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => Some(it.as_path()),
            VfsPathRepr::VirtualPath(_) => None,
        }
    }

    /// Creates a new `VfsPath` with `path` adjoined to `self`.
    pub fn join(&self, path: &str) -> Option<VfsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => {
                let res = it.join(path).normalize();
                Some(VfsPath(VfsPathRepr::PathBuf(res)))
            }
            VfsPathRepr::VirtualPath(it) => {
                let res = it.join(path)?;
                Some(VfsPath(VfsPathRepr::VirtualPath(res)))
            }
        }
    }

    /// Remove the last component of `self` if there is one.
    ///
    /// If `self` has no component, returns `false`; else returns `true`.
    ///
    /// # Example
    ///
    /// ```
    /// # use vfs::{AbsPathBuf, VfsPath};
    /// let mut path = VfsPath::from(AbsPathBuf::assert("/foo/bar".into()));
    /// assert!(path.pop());
    /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/foo".into())));
    /// assert!(path.pop());
    /// assert_eq!(path, VfsPath::from(AbsPathBuf::assert("/".into())));
    /// assert!(!path.pop());
    /// ```
    pub fn pop(&mut self) -> bool {
        match &mut self.0 {
            VfsPathRepr::PathBuf(it) => it.pop(),
            VfsPathRepr::VirtualPath(it) => it.pop(),
        }
    }

    /// Returns `true` if `other` is a prefix of `self`.
    pub fn starts_with(&self, other: &VfsPath) -> bool {
        match (&self.0, &other.0) {
            (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::PathBuf(_), _) => false,
            (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::VirtualPath(_), _) => false,
        }
    }

    /// Returns the `VfsPath` without its final component, if there is one.
    ///
    /// Returns [`None`] if the path is a root or prefix.
    pub fn parent(&self) -> Option<VfsPath> {
        let mut parent = self.clone();
        if parent.pop() {
            Some(parent)
        } else {
            None
        }
    }

    /// Returns `self`'s base name and file extension.
    pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        match &self.0 {
            VfsPathRepr::PathBuf(p) => Some((
                p.file_stem()?.to_str()?,
                p.extension().and_then(|extension| extension.to_str()),
            )),
            VfsPathRepr::VirtualPath(p) => p.name_and_extension(),
        }
    }

    /// **Don't make this `pub`**
    ///
    /// Encode the path in the given buffer.
    ///
    /// The encoding will be `0` if [`AbsPathBuf`], `1` if [`VirtualPath`], followed
    /// by `self`'s representation.
    ///
    /// Note that this encoding is dependent on the operating system.
    pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
        let tag = match &self.0 {
            VfsPathRepr::PathBuf(_) => 0,
            VfsPathRepr::VirtualPath(_) => 1,
        };
        buf.push(tag);
        match &self.0 {
            VfsPathRepr::PathBuf(path) => {
                #[cfg(windows)]
                {
                    use windows_paths::Encode;
                    let path: &std::path::Path = path.as_ref();
                    let components = path.components();
                    let mut add_sep = false;
                    for component in components {
                        if add_sep {
                            windows_paths::SEP.encode(buf);
                        }
                        let len_before = buf.len();
                        match component {
                            std::path::Component::Prefix(prefix) => {
                                // kind() returns a normalized and comparable path prefix.
                                prefix.kind().encode(buf);
                            }
                            std::path::Component::RootDir => {
                                if !add_sep {
                                    component.as_os_str().encode(buf);
                                }
                            }
                            _ => component.as_os_str().encode(buf),
                        }

                        // some components may be encoded empty
                        add_sep = len_before != buf.len();
                    }
                }
                #[cfg(unix)]
                {
                    use std::os::unix::ffi::OsStrExt;
                    buf.extend(path.as_os_str().as_bytes());
                }
                #[cfg(not(any(windows, unix)))]
                {
                    buf.extend(path.as_os_str().to_string_lossy().as_bytes());
                }
            }
            VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()),
        }
    }
}

#[cfg(windows)]
mod windows_paths {
    pub(crate) trait Encode {
        fn encode(&self, buf: &mut Vec<u8>);
    }

    impl Encode for std::ffi::OsStr {
        fn encode(&self, buf: &mut Vec<u8>) {
            use std::os::windows::ffi::OsStrExt;
            for wchar in self.encode_wide() {
                buf.extend(wchar.to_le_bytes().iter().copied());
            }
        }
    }

    impl Encode for u8 {
        fn encode(&self, buf: &mut Vec<u8>) {
            let wide = *self as u16;
            buf.extend(wide.to_le_bytes().iter().copied())
        }
    }

    impl Encode for &str {
        fn encode(&self, buf: &mut Vec<u8>) {
            debug_assert!(self.is_ascii());
            for b in self.as_bytes() {
                b.encode(buf)
            }
        }
    }

    pub(crate) const SEP: &str = "\\";
    const VERBATIM: &str = "\\\\?\\";
    const UNC: &str = "UNC";
    const DEVICE: &str = "\\\\.\\";
    const COLON: &str = ":";

    impl Encode for std::path::Prefix<'_> {
        fn encode(&self, buf: &mut Vec<u8>) {
            match self {
                std::path::Prefix::Verbatim(c) => {
                    VERBATIM.encode(buf);
                    c.encode(buf);
                }
                std::path::Prefix::VerbatimUNC(server, share) => {
                    VERBATIM.encode(buf);
                    UNC.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::VerbatimDisk(d) => {
                    VERBATIM.encode(buf);
                    d.encode(buf);
                    COLON.encode(buf);
                }
                std::path::Prefix::DeviceNS(device) => {
                    DEVICE.encode(buf);
                    device.encode(buf);
                }
                std::path::Prefix::UNC(server, share) => {
                    SEP.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::Disk(d) => {
                    d.encode(buf);
                    COLON.encode(buf);
                }
            }
        }
    }
    #[test]
    fn paths_encoding() {
        // drive letter casing agnostic
        test_eq("C:/x.rs", "c:/x.rs");
        // separator agnostic
        test_eq("C:/x/y.rs", "C:\\x\\y.rs");

        fn test_eq(a: &str, b: &str) {
            let mut b1 = Vec::new();
            let mut b2 = Vec::new();
            vfs(a).encode(&mut b1);
            vfs(b).encode(&mut b2);
            assert_eq!(b1, b2);
        }
    }

    #[test]
    fn test_sep_root_dir_encoding() {
        let mut buf = Vec::new();
        vfs("C:/x/y").encode(&mut buf);
        assert_eq!(&buf, &[0, 67, 0, 58, 0, 92, 0, 120, 0, 92, 0, 121, 0])
    }

    #[cfg(test)]
    fn vfs(str: &str) -> super::VfsPath {
        use super::{AbsPathBuf, VfsPath};
        use std::convert::TryFrom;
        VfsPath::from(AbsPathBuf::try_from(str).unwrap())
    }
}

/// Internal, private representation of [`VfsPath`].
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
enum VfsPathRepr {
    PathBuf(AbsPathBuf),
    VirtualPath(VirtualPath),
}

impl From<AbsPathBuf> for VfsPath {
    fn from(v: AbsPathBuf) -> Self {
        VfsPath(VfsPathRepr::PathBuf(v.normalize()))
    }
}

impl fmt::Display for VfsPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f),
        }
    }
}

impl fmt::Debug for VfsPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Debug for VfsPathRepr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self {
            VfsPathRepr::PathBuf(it) => fmt::Debug::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Debug::fmt(&it, f),
        }
    }
}

/// `/`-separated virtual path.
///
/// This is used to describe files that do not reside on the file system.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
struct VirtualPath(String);

impl VirtualPath {
    /// Returns `true` if `other` is a prefix of `self` (as strings).
    fn starts_with(&self, other: &VirtualPath) -> bool {
        self.0.starts_with(&other.0)
    }

    /// Remove the last component of `self`.
    ///
    /// This will find the last `'/'` in `self`, and remove everything after it,
    /// including the `'/'`.
    ///
    /// If `self` contains no `'/'`, returns `false`; else returns `true`.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut path = VirtualPath("/foo/bar".to_string());
    /// path.pop();
    /// assert_eq!(path.0, "/foo");
    /// path.pop();
    /// assert_eq!(path.0, "");
    /// ```
    fn pop(&mut self) -> bool {
        let pos = match self.0.rfind('/') {
            Some(pos) => pos,
            None => return false,
        };
        self.0 = self.0[..pos].to_string();
        true
    }

    /// Append the given *relative* path `path` to `self`.
    ///
    /// This will resolve any leading `"../"` in `path` before appending it.
    ///
    /// Returns [`None`] if `path` has more leading `"../"` than the number of
    /// components in `self`.
    ///
    /// # Notes
    ///
    /// In practice, appending here means `self/path` as strings.
    fn join(&self, mut path: &str) -> Option<VirtualPath> {
        let mut res = self.clone();
        while path.starts_with("../") {
            if !res.pop() {
                return None;
            }
            path = &path["../".len()..]
        }
        path = path.trim_start_matches("./");
        res.0 = format!("{}/{}", res.0, path);
        Some(res)
    }

    /// Returns `self`'s base name and file extension.
    ///
    /// # Returns
    /// - `None` if `self` ends with `"//"`.
    /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at
    /// the start.
    /// - `Some((name, Some(extension))` else.
    ///
    /// # Note
    /// The extension will not contains `.`. This means `"/foo/bar.baz.rs"` will
    /// return `Some(("bar.baz", Some("rs"))`.
    fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 };
        let file_name = match file_path.rfind('/') {
            Some(position) => &file_path[position + 1..],
            None => file_path,
        };

        if file_name.is_empty() {
            None
        } else {
            let mut file_stem_and_extension = file_name.rsplitn(2, '.');
            let extension = file_stem_and_extension.next();
            let file_stem = file_stem_and_extension.next();

            match (file_stem, extension) {
                (None, None) => None,
                (None | Some(""), Some(_)) => Some((file_name, None)),
                (Some(file_stem), extension) => Some((file_stem, extension)),
            }
        }
    }
}

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


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

extern "C" {
    /// In *Release* builds, the C library links directly against `malloc` and `free`.
    ///
    /// When freeing memory that was allocated by C code, use `free` directly.
    #[cfg(not(test))]
    #[link_name = "free"]
    pub fn free_ptr(ptr: *mut c_void);

    /// In *Test* builds, the C library is compiled with the `TREE_SITTER_TEST` macro,
    /// so all calls to `malloc`, `free`, etc are linked against wrapper functions
    /// called `ts_record_malloc`, `ts_record_free`, etc. These symbols are defined
    /// in the `tree_sitter_cli::tests::helpers::allocations` module.
    ///
    /// When freeing memory that was allocated by C code, use the `free` function
    /// from that module.
    #[cfg(test)]
    #[link_name = "ts_record_free"]
    pub fn free_ptr(ptr: *mut c_void);

    /// In *Debug* builds, the C library is compiled the same as in test builds: using
    /// the wrapper functions. This prevents the C library from having to be recompiled
    /// constantly when switching between running tests and compiling with RLS.
    ///
    /// But we don't want to actually record allocations when running the library in
    /// debug mode, so we define symbols like `ts_record_malloc` to just delegate to
    /// the normal `malloc` functions.
    #[cfg(all(debug_assertions, not(test)))]
    fn malloc(size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn calloc(count: usize, size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn free(ptr: *mut c_void);
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_malloc(size: usize) -> *const c_void {
    malloc(size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_calloc(count: usize, size: usize) -> *const c_void {
    calloc(count, size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_realloc(ptr: *mut c_void, size: usize) -> *const c_void {
    realloc(ptr, size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_free(ptr: *mut c_void) {
    free(ptr)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
extern "C" fn ts_toggle_allocation_recording(_: bool) -> bool {
    false
}

pub struct CBufferIter<T> {
    ptr: *mut T,
    count: usize,
    i: usize,
}

impl<T> CBufferIter<T> {
    pub unsafe fn new(ptr: *mut T, count: usize) -> Self {
        Self { ptr, count, i: 0 }
    }
}

impl<T: Copy> Iterator for CBufferIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.count {
            None
        } else {
            self.i += 1;
            Some(unsafe { *self.ptr.offset(i as isize) })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.count - self.i;
        (remaining, Some(remaining))
    }
}

impl<T: Copy> ExactSizeIterator for CBufferIter<T> {}

impl<T> Drop for CBufferIter<T> {
    fn drop(&mut self) {
        unsafe {
            free_ptr(self.ptr as *mut c_void);
        }
    }
}
<commit_msg>Fix debug/release conditional compilation flags for free()<commit_after>use std::os::raw::c_void;

extern "C" {
    /// In *Release* builds, the C library links directly against `malloc` and `free`.
    ///
    /// When freeing memory that was allocated by C code, use `free` directly.
    #[cfg(not(debug_assertions))]
    #[link_name = "free"]
    pub fn free_ptr(ptr: *mut c_void);

    /// In *Test* builds, the C library is compiled with the `TREE_SITTER_TEST` macro,
    /// so all calls to `malloc`, `free`, etc are linked against wrapper functions
    /// called `ts_record_malloc`, `ts_record_free`, etc. These symbols are defined
    /// in the `tree_sitter_cli::tests::helpers::allocations` module.
    ///
    /// When freeing memory that was allocated by C code, use the `free` function
    /// from that module.
    #[cfg(debug_assertions)]
    #[link_name = "ts_record_free"]
    pub fn free_ptr(ptr: *mut c_void);

    /// In *Debug* builds, the C library is compiled the same as in test builds: using
    /// the wrapper functions. This prevents the C library from having to be recompiled
    /// constantly when switching between running tests and compiling with RLS.
    ///
    /// But we don't want to actually record allocations when running the library in
    /// debug mode, so we define symbols like `ts_record_malloc` to just delegate to
    /// the normal `malloc` functions.
    #[cfg(all(debug_assertions, not(test)))]
    fn malloc(size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn calloc(count: usize, size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
    #[cfg(all(debug_assertions, not(test)))]
    fn free(ptr: *mut c_void);
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_malloc(size: usize) -> *const c_void {
    malloc(size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_calloc(count: usize, size: usize) -> *const c_void {
    calloc(count, size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_realloc(ptr: *mut c_void, size: usize) -> *const c_void {
    realloc(ptr, size)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_free(ptr: *mut c_void) {
    free(ptr)
}

#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
extern "C" fn ts_toggle_allocation_recording(_: bool) -> bool {
    false
}

pub struct CBufferIter<T> {
    ptr: *mut T,
    count: usize,
    i: usize,
}

impl<T> CBufferIter<T> {
    pub unsafe fn new(ptr: *mut T, count: usize) -> Self {
        Self { ptr, count, i: 0 }
    }
}

impl<T: Copy> Iterator for CBufferIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.count {
            None
        } else {
            self.i += 1;
            Some(unsafe { *self.ptr.offset(i as isize) })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.count - self.i;
        (remaining, Some(remaining))
    }
}

impl<T: Copy> ExactSizeIterator for CBufferIter<T> {}

impl<T> Drop for CBufferIter<T> {
    fn drop(&mut self) {
        unsafe {
            free_ptr(self.ptr as *mut c_void);
        }
    }
}
<|endoftext|>