<commit_before>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

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

use hir_expand::{
    hygiene::Hygiene,
    name::{AsName, Name},
};
use ra_db::CrateId;
use ra_syntax::ast;

use crate::{type_ref::TypeRef, InFile};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_simple_segments(
        kind: PathKind,
        segments: impl IntoIterator<Item = Name>,
    ) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
        name_ref.as_name().into()
    }

    /// Converts an `tt::Ident` into a single-identifier `Path`.
    pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
        ident.as_name().into()
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::UseItem>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if self.kind != PathKind::Plain || self.segments.len() > 1 {
            return None;
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    mod_path: ModPath,
    /// Invariant: the same len as self.path.segments
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<(Name, TypeRef)>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    // or lifetime...
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// Type based path like `<T>::foo`
    Type(Box<TypeRef>),
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// DEPRECATED: It does not handle `$crate` from macro call.
    pub fn from_ast(path: ast::Path) -> Option<Path> {
        lower::lower_path(path, &Hygiene::new_unhygienic())
    }

    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts an `ast::NameRef` into a single-identifier `Path`.
    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
        Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] }
    }

    /// `true` if this path is just a standalone `self`
    pub fn is_self(&self) -> bool {
        self.mod_path.is_self()
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (std::iter::IntoIterator) => {};
    (std::result::Result) => {};
    (std::ops::Range) => {};
    (std::ops::RangeFrom) => {};
    (std::ops::RangeFull) => {};
    (std::ops::RangeTo) => {};
    (std::ops::RangeToInclusive) => {};
    (std::ops::RangeInclusive) => {};
    (std::boxed::Box) => {};
    (std::future::Future) => {};
    (std::ops::Try) => {};
    (std::ops::Neg) => {};
    (std::ops::Not) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<commit_msg>Move PathKindUp<commit_after>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

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

use hir_expand::{
    hygiene::Hygiene,
    name::{AsName, Name},
};
use ra_db::CrateId;
use ra_syntax::ast;

use crate::{type_ref::TypeRef, InFile};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// Type based path like `<T>::foo`
    Type(Box<TypeRef>),
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_simple_segments(
        kind: PathKind,
        segments: impl IntoIterator<Item = Name>,
    ) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
        name_ref.as_name().into()
    }

    /// Converts an `tt::Ident` into a single-identifier `Path`.
    pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
        ident.as_name().into()
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::UseItem>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if self.kind != PathKind::Plain || self.segments.len() > 1 {
            return None;
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    mod_path: ModPath,
    /// Invariant: the same len as self.path.segments
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<(Name, TypeRef)>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    // or lifetime...
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// DEPRECATED: It does not handle `$crate` from macro call.
    pub fn from_ast(path: ast::Path) -> Option<Path> {
        lower::lower_path(path, &Hygiene::new_unhygienic())
    }

    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts an `ast::NameRef` into a single-identifier `Path`.
    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
        Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] }
    }

    /// `true` if this path is just a standalone `self`
    pub fn is_self(&self) -> bool {
        self.mod_path.is_self()
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (std::iter::IntoIterator) => {};
    (std::result::Result) => {};
    (std::ops::Range) => {};
    (std::ops::RangeFrom) => {};
    (std::ops::RangeFull) => {};
    (std::ops::RangeTo) => {};
    (std::ops::RangeToInclusive) => {};
    (std::ops::RangeInclusive) => {};
    (std::boxed::Box) => {};
    (std::future::Future) => {};
    (std::ops::Try) => {};
    (std::ops::Neg) => {};
    (std::ops::Not) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<|endoftext|>


<commit_before>pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::{HashMap, HashSet},
    fmt::Debug,
    rc::Rc,
};

pub use crate::*;
pub use api::*;
pub use ecs::*;
pub use orbtk_api::css_engine::{Selector, Theme};
pub use orbtk_render::prelude::Image;
pub use proc_macros::*;
pub use theme::{colors, default_theme, fonts, light_theme, vector_graphics::material_font_icons};
pub use utils::*;
<commit_msg>widgets/prelude: incorporate the new vector_graphics fonts<commit_after>pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::{HashMap, HashSet},
    fmt::Debug,
    rc::Rc,
};

pub use crate::*;
pub use api::*;
pub use ecs::*;
pub use orbtk_api::css_engine::{Selector, Theme};
pub use orbtk_render::prelude::Image;
pub use proc_macros::*;
pub use theme::{
    colors,
    default_theme,
    fonts,
    light_theme,
    vector_graphics::{
	material_icons_font_ttf,
	material_icons_font,
	material_icons_round_font,
	material_icons_sharp_font,
	material_icons_twotone_font,
    }
};
pub use utils::*;
<|endoftext|>


<commit_before>extern crate image;
extern crate img_hash;
extern crate rayon;
extern crate rusttype;

use img_hash::demo::*;
use image::*;
use rusttype::{Scale, Point};

const HASH_WIDTH: u32 = 9;
const HASH_HEIGHT: u32 = 8;

const WHITE_A: Rgba<u8> = Rgba { data: [255; 4] };
const BLACK: Rgb<u8> = Rgb{ data: [0, 0, 0 ] };
const RED: Rgb<u8> = Rgb { data: [255, 0, 0] };
const GREEN: Rgb<u8> = Rgb { data: [0, 255, 0] };

macro_rules! handle(
    ($try:expr) => {
        if let Err(e) = $try {
            println!("{}", e);
        }
    }
);

fn main() -> Result<(), String> {
    let ref ctxt = DemoCtxt::init("demo_gradient", "HashAlg::Gradient")?;

    println!("generating Gradient hash demo");

    println!("generating grayscale animation");
    // 4 FPS over 5 seconds
    let grayscale_anim = ctxt.animate_grayscale(&ctxt.image, 20, 25);

    let ref grayscale = grayscale_anim.last().unwrap().buffer().clone();

    rayon::scope(move |s| {
        s.spawn(move |s| {
            println!("saving grayscale animation");
            handle!(ctxt.save_gif("grayscale", grayscale_anim));
        });

        s.spawn(move |s| {
            println!("generating resize animation");
            let resize_anim = ctxt.animate_resize(grayscale, HASH_WIDTH, HASH_HEIGHT, 20, 25);

            s.spawn(move |s| {
                println!("saving resize animation");
                handle!(ctxt.save_gif("resize", resize_anim));
            });
        });

        s.spawn(move |s| {
            println!("generating gradient hash animation");
            let gradient_anim = animate_gradient(ctxt, grayscale);

            s.spawn(move |s| {
                println!("saving gradient hash animation");
                handle!(ctxt.save_gif("gradient_hash", gradient_anim));
            })
        })

    });

    Ok(())
}

fn animate_gradient(ctxt: &DemoCtxt, grayscale: &RgbaImage) -> Vec<Frame> {
    // the final resized image
    let resized_small = imageops::resize(grayscale, HASH_WIDTH, HASH_HEIGHT, Lanczos3);

    let gif_height = ctxt.width / 2;

    let mut background = ImageBuffer::from_pixel(ctxt.width, gif_height, WHITE_A);

    // half the width with 10% padding
    let resize_width = (ctxt.width / 2 * 9) / 10;
    // match the resize aspect ratio
    let resize_height = resize_width * HASH_HEIGHT / HASH_WIDTH;

    // nearest filter will retain the individual pixels
    let resized = imageops::resize(&resized_small, resize_width, resize_height, Nearest);

    // center the resized image in the left half of `background`
    let overlay_x = (ctxt.width / 2 - resize_width) / 2;
    let overlay_y = (gif_height - resize_height) / 2;

    imageops::overlay(&mut background, &resized, overlay_x, overlay_y);

    let pixel_width = resize_width / HASH_WIDTH;
    let pixel_height = resize_height / HASH_HEIGHT;

    // the inner dimensions of the outline, should encompass 2x1 of the large pixels
    let outline_inner_width = pixel_width * 2;
    let outline_inner_height = pixel_height;

    // add 10% as the outline's thickness
    let outline_outer_width = outline_inner_width * 11 / 10;
    let outline_outer_height = outline_inner_height * 11 / 10;

    // if `x` is less than the former or greater than the latter, AND
    let outline_lower_x = outline_outer_width - outline_inner_width;
    let outline_upper_x = outline_outer_width - outline_lower_x;

    // if `y` is less than the former or greater than the latter, THEN
    let outline_lower_y = outline_outer_height - outline_inner_height;
    let outline_upper_y = outline_outer_height - outline_lower_y;

    // draw a red outline
    let outline = RgbaImage::from_fn(outline_outer_width, outline_outer_height, |x, y| {
        let x_in_outline = x < outline_lower_x || x > outline_upper_x;
        let y_in_outline = y < outline_lower_y || y > outline_upper_y;

        let alpha = if x_in_outline || y_in_outline { 255 } else { 0 };
        let mut color = RED.to_rgba();
        color[3] = alpha;
        color
    });

    let mut bitstring = Bitstring::new();

    // we touch HASH_HEIGHT * (HASH_WIDTH - 1) pixels
    (0 .. HASH_HEIGHT).flat_map(|y| (0 .. HASH_WIDTH - 1).map(move |x| (x, y)))
        .map(|(x, y)| {
            let mut frame = background.clone();

            imageops::overlay(&mut frame, &outline,
                              overlay_x + outline_inner_width / 2 * x,
                              overlay_y + outline_inner_height * y);

            let left = *resized_small.get_pixel(x, y);
            let right = *resized_small.get_pixel(x + 1, y);

            let left_pixel = ImageBuffer::from_pixel(pixel_width, pixel_height, left);
            let right_pixel = ImageBuffer::from_pixel(pixel_width, pixel_height, right);

            let bit = left.to_luma()[0] > right.to_luma()[0];

            // position the left pixel in the second third of the image's width
            let left_pixel_x = ctxt.width / 3 * 2;
            let right_pixel_x = left_pixel_x + (pixel_width * 2);
            let pixel_y = gif_height / 4;

            // between the two pixels draw either `<` or `>`
            let comp = if bit { '>' } else { '⩽' };
            bitstring.push_bit(bit);

            let bit_color = if bit { GREEN } else { RED };

            let comp_glyph = center_in_area(
                ctxt.font.glyph(comp)
                .scaled(Scale { x: pixel_width as f32, y: pixel_height as f32 })
                .positioned(Point { x: (left_pixel_x + pixel_width) as f32, y: pixel_y as f32 }),
                pixel_width, pixel_height);

            imageops::overlay(&mut frame, &left_pixel, left_pixel_x, pixel_y);
            imageops::overlay(&mut frame, &right_pixel, right_pixel_x, pixel_y);

            draw_glyph(&mut frame, &comp_glyph, &bit_color);

            let string_x = ctxt.width / 2 * 11 / 10;
            let string_y = gif_height * 3 / 4;
            ctxt.layout_text(bitstring.as_str(), string_x, string_y).enumerate()
                .for_each(|(i, g)| {
                    let color = if i + 1 == bitstring.as_str().len() { bit_color } else { BLACK };
                    draw_glyph(&mut frame, &g, &color)
                });

            // run faster after the first couple rows
            let delay = if y < 2 { 50 } else { 8 };
            Frame::from_parts(frame, 0, 0, delay.into())
        })
        .collect()
}
<commit_msg>design tweaks and fixes<commit_after>extern crate image;
extern crate img_hash;
extern crate rayon;
extern crate rusttype;

use img_hash::demo::*;
use image::*;
use rusttype::{Scale, Point};

const HASH_WIDTH: u32 = 9;
const HASH_HEIGHT: u32 = 8;

const WHITE_A: Rgba<u8> = Rgba { data: [255; 4] };
const BLACK: Rgb<u8> = Rgb{ data: [0, 0, 0 ] };
const RED: Rgb<u8> = Rgb { data: [255, 0, 0] };
const GREEN: Rgb<u8> = Rgb { data: [0, 255, 0] };

macro_rules! handle(
    ($try:expr) => {
        if let Err(e) = $try {
            println!("{}", e);
        }
    }
);

fn main() -> Result<(), String> {
    let ref ctxt = DemoCtxt::init("demo_gradient", "HashAlg::Gradient")?;

    println!("generating Gradient hash demo");

    println!("generating grayscale animation");
    // 4 FPS over 5 seconds
    let grayscale_anim = ctxt.animate_grayscale(&ctxt.image, 20, 25);

    let ref grayscale = grayscale_anim.last().unwrap().buffer().clone();

    rayon::scope(move |s| {
        s.spawn(move |s| {
            println!("saving grayscale animation");
            handle!(ctxt.save_gif("grayscale", grayscale_anim));
        });

        s.spawn(move |s| {
            println!("generating resize animation");
            let resize_anim = ctxt.animate_resize(grayscale, HASH_WIDTH, HASH_HEIGHT, 20, 25);

            s.spawn(move |s| {
                println!("saving resize animation");
                handle!(ctxt.save_gif("resize", resize_anim));
            });
        });

        s.spawn(move |s| {
            println!("generating gradient hash animation");
            let gradient_anim = animate_gradient(ctxt, grayscale);

            s.spawn(move |s| {
                println!("saving gradient hash animation");
                handle!(ctxt.save_gif("gradient_hash", gradient_anim));
            })
        })

    });

    Ok(())
}

/// Multiply a `u32` by an `f32` with a truncated result
fn fmul(x: u32, y: f32) -> u32 {
    (x as f32 * y) as u32
}

fn animate_gradient(ctxt: &DemoCtxt, grayscale: &RgbaImage) -> Vec<Frame> {
    // the final resized image
    let resized_small = imageops::resize(grayscale, HASH_WIDTH, HASH_HEIGHT, Lanczos3);

    let gif_height = ctxt.width / 2;

    let mut background = ImageBuffer::from_pixel(ctxt.width, gif_height, WHITE_A);

    // half the width with 10% padding
    let resize_width = fmul(ctxt.width / 2, 0.9);
    // match the resize aspect ratio
    let resize_height = resize_width * HASH_HEIGHT / HASH_WIDTH;

    // nearest filter will retain the individual pixels
    let resized = imageops::resize(&resized_small, resize_width, resize_height, Nearest);

    // center the resized image in the left half of `background`
    let overlay_x = (ctxt.width / 2 - resize_width) / 2;
    let overlay_y = (gif_height - resize_height) / 2;

    imageops::overlay(&mut background, &resized, overlay_x, overlay_y);

    let pixel_width = resize_width / HASH_WIDTH;
    let pixel_height = resize_height / HASH_HEIGHT;

    // the inner dimensions of the outline, should encompass 2x1 of the large pixels
    let outline_inner_width = pixel_width * 2;
    let outline_inner_height = pixel_height;

    // add 10% as the outline's thickness
    let outline_outer_width = fmul(outline_inner_width, 1.1);
    let outline_outer_height = fmul(outline_inner_height, 1.1);

    // if `x` is less than the former or greater than the latter, AND
    let outline_lower_x = (outline_outer_width - outline_inner_width) / 2;
    let outline_upper_x = outline_outer_width - outline_lower_x;

    // if `y` is less than the former or greater than the latter, THEN
    let outline_lower_y = (outline_outer_height - outline_inner_height) / 2;
    let outline_upper_y = outline_outer_height - outline_lower_y;

    // subtract the thickness of the outline from its overall offset
    let outline_x = overlay_x - outline_lower_x;
    let outline_y = overlay_y - outline_lower_y;

    // draw a red outline
    let red_outline = RgbaImage::from_fn(outline_outer_width, outline_outer_height, |x, y| {
        let x_in_outline = x < outline_lower_x || x >= outline_upper_x;
        let y_in_outline = y < outline_lower_y || y >= outline_upper_y;

        let alpha = if x_in_outline || y_in_outline { 255 } else { 0 };
        let mut color = RED.to_rgba();
        color[3] = alpha;
        color
    });

    let green_outline = RgbaImage::from_fn(outline_outer_width, outline_outer_height, |x, y| {
        let x_in_outline = x < outline_lower_x || x > outline_upper_x;
        let y_in_outline = y < outline_lower_y || y > outline_upper_y;

        let alpha = if x_in_outline || y_in_outline { 255 } else { 0 };
        let mut color = GREEN.to_rgba();
        color[3] = alpha;
        color
    });

    let mut bitstring = Bitstring::new();

    // we touch HASH_HEIGHT * (HASH_WIDTH - 1) pixels
    (0 .. HASH_HEIGHT).flat_map(|y| (0 .. HASH_WIDTH - 1).map(move |x| (x, y)))
        .map(|(x, y)| {
            let mut frame = background.clone();

            let left = *resized_small.get_pixel(x, y);
            let right = *resized_small.get_pixel(x + 1, y);

            let left_pixel = ImageBuffer::from_pixel(pixel_width, pixel_height, left);
            let right_pixel = ImageBuffer::from_pixel(pixel_width, pixel_height, right);

            let bit = left.to_luma()[0] > right.to_luma()[0];

            imageops::overlay(&mut frame, if bit { &green_outline } else { &red_outline },
                              outline_x + pixel_width * x, outline_y + pixel_height * y);

            // position the left pixel in the second third of the image's width
            let left_pixel_x = ctxt.width / 3 * 2;
            let right_pixel_x = left_pixel_x + (pixel_width * 2);
            let pixel_y = gif_height / 4;

            // between the two pixels draw either `<` or `>`
            let comp = if bit { '>' } else { '⩽' };
            bitstring.push_bit(bit);

            let bit_color = if bit { GREEN } else { RED };

            let comp_glyph = center_in_area(
                ctxt.font.glyph(comp)
                .scaled(Scale { x: pixel_width as f32, y: pixel_height as f32 })
                .positioned(Point { x: (left_pixel_x + pixel_width) as f32, y: pixel_y as f32 }),
                pixel_width, pixel_height);

            imageops::overlay(&mut frame, &left_pixel, left_pixel_x, pixel_y);
            imageops::overlay(&mut frame, &right_pixel, right_pixel_x, pixel_y);

            draw_glyph(&mut frame, &comp_glyph, &bit_color);

            // place the string just after the horizontal halfway point with some padding
            let string_x = fmul(ctxt.width / 2, 1.1);
            let string_y = gif_height * 3 / 4;
            ctxt.layout_text(bitstring.as_str(), string_x, string_y).enumerate()
                .for_each(|(i, g)| {
                    let color = if i + 1 == bitstring.as_str().len() { bit_color } else { BLACK };
                    draw_glyph(&mut frame, &g, &color)
                });

            // run faster after the first couple rows
            let delay = if y < 2 { 50 } else { 8 };
            Frame::from_parts(frame, 0, 0, delay.into())
        })
        .collect()
}
<|endoftext|>


<commit_before>#[allow(non_camel_case_types)]
pub enum ErrorType {
    PSM_OK = 0,
    PSM_OK_NO_PROGRESS = 1,
    PSM_PARAM_ERR = 3,
    PSM_NO_MEMORY = 4,
    PSM_INIT_NOT_INIT = 5,
    PSM_INIT_BAD_API_VERSION = 6,
    PSM_NO_AFFINITY = 7,
    PSM_INTERNAL_ERR = 8,
    PSM_SHMEM_SEGMENT_ERR = 9,
    PSM_OPT_READONLY = 10,
    PSM_TIMEOUT = 11,
    PSM_TOO_MANY_ENDPOINTS = 12,
    PSM_IS_FINALIZED = 13,
    PSM_EP_WAS_CLOSED = 20,
    PSM_EP_NO_DEVICE = 21,
    PSM_EP_UNIT_NOT_FOUND = 22,
    PSM_EP_DEVICE_FAILURE = 23,
    PSM_EP_CLOSE_TIMEOUT = 24,
    PSM_EP_NO_PORTS_AVAIL = 25,
    PSM_EP_NO_NETWORK = 26,
    PSM_EP_INVALID_UUID_KEY = 27,
    PSM_EP_NO_RESOURCES = 28,
    PSM_EPID_UNKNOWN = 40,
    PSM_EPID_UNREACHABLE = 41,
    PSM_EPID_INVALID_NODE = 43,
    PSM_EPID_INVALID_MTU =  44,
    PSM_EPID_INVALID_UUID_KEY = 45,
    PSM_EPID_INVALID_VERSION = 46,
    PSM_EPID_INVALID_CONNECT = 47,
    PSM_EPID_ALREADY_CONNECTED = 48,
    PSM_EPID_NETWORK_ERROR = 49,
    PSM_EPID_INVALID_PKEY = 50,
    PSM_EPID_PATH_RESOLUTION = 51,
    PSM_MQ_NO_COMPLETIONS = 60,
    PSM_MQ_TRUNCATION = 61,
    PSM_AM_INVALID_REPLY = 70,
    PSM_ERROR_LAST = 80
}

pub struct Error {
  pub error: ErrorType,
  pub error_str: &'static str
  // TODO: add a fn for psm_error_token and remane
}

impl Error {
  pub fn new(error: ErrorType, error_str: &'static str)-> Error {
    Error { error: error, error_str: error_str }
  }

  pub fn error_type_to_string(self) -> &'static str {
    "NONE()"
  }
}
<commit_msg>Added a space on Error::new. Use Error::new and not built-in constructor.<commit_after>#[allow(non_camel_case_types)]
pub enum ErrorType {
    PSM_OK = 0,
    PSM_OK_NO_PROGRESS = 1,
    PSM_PARAM_ERR = 3,
    PSM_NO_MEMORY = 4,
    PSM_INIT_NOT_INIT = 5,
    PSM_INIT_BAD_API_VERSION = 6,
    PSM_NO_AFFINITY = 7,
    PSM_INTERNAL_ERR = 8,
    PSM_SHMEM_SEGMENT_ERR = 9,
    PSM_OPT_READONLY = 10,
    PSM_TIMEOUT = 11,
    PSM_TOO_MANY_ENDPOINTS = 12,
    PSM_IS_FINALIZED = 13,
    PSM_EP_WAS_CLOSED = 20,
    PSM_EP_NO_DEVICE = 21,
    PSM_EP_UNIT_NOT_FOUND = 22,
    PSM_EP_DEVICE_FAILURE = 23,
    PSM_EP_CLOSE_TIMEOUT = 24,
    PSM_EP_NO_PORTS_AVAIL = 25,
    PSM_EP_NO_NETWORK = 26,
    PSM_EP_INVALID_UUID_KEY = 27,
    PSM_EP_NO_RESOURCES = 28,
    PSM_EPID_UNKNOWN = 40,
    PSM_EPID_UNREACHABLE = 41,
    PSM_EPID_INVALID_NODE = 43,
    PSM_EPID_INVALID_MTU =  44,
    PSM_EPID_INVALID_UUID_KEY = 45,
    PSM_EPID_INVALID_VERSION = 46,
    PSM_EPID_INVALID_CONNECT = 47,
    PSM_EPID_ALREADY_CONNECTED = 48,
    PSM_EPID_NETWORK_ERROR = 49,
    PSM_EPID_INVALID_PKEY = 50,
    PSM_EPID_PATH_RESOLUTION = 51,
    PSM_MQ_NO_COMPLETIONS = 60,
    PSM_MQ_TRUNCATION = 61,
    PSM_AM_INVALID_REPLY = 70,
    PSM_ERROR_LAST = 80
}

pub struct Error {
  pub error: ErrorType,
  pub error_str: &'static str
  // TODO: add a fn for psm_error_token and remane
}

impl Error {
  pub fn new(error: ErrorType, error_str: &'static str) -> Error {
    Error::new(error, error_str)
  }

  pub fn error_type_to_string(self) -> &'static str {
    "NONE()"
  }
}
<|endoftext|>


<commit_before>use glob::glob;
use hyper::client::HttpConnector;
use hyper::rt::{self, Future, Stream};
use hyper::{header, Body, Chunk, Client, Request, Response};
use hyper_tls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::sync::mpsc;
use structs::{CliError, Config, Member, PublicKey, RateLimit, Repo, Sector, SectorGroup, Team};

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_contents_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut contents = String::new();
        f.read_to_string(&mut contents)?;
        Ok((metadata, contents))
    }

    fn store_contents_to_cache(&self, url: &str, contents: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_contents_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let contents = serde_json::ser::to_string(&all_contents)?;
        self.store_contents_to_cache(url, &contents)?;
        Ok(contents)
    }

    fn build_request(&self, url: &str) -> Result<Request<Body>, CliError> {
        let token = String::from("token ") + &self.conf.token;
        Request::get(url).header(header::AUTHORIZATION, token.as_str())
                         .header(header::USER_AGENT, "sectora")
                         .body(Body::empty())
                         .map_err(CliError::from)
    }

    fn build_page_request(&self, url: &str, page: u64) -> Result<Request<Body>, CliError> {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn build_https_client() -> Result<Client<HttpsConnector<HttpConnector>>, CliError> {
        let https = HttpsConnector::new(4)?;
        Ok(Client::builder().build(https))
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, CliError> {
        let concat_body = |res: Response<Body>| res.into_body().concat2();
        let (tx, rx) = mpsc::sync_channel(1);
        let ex = tx.clone();
        let send_res = move |r| tx.send(Ok(r)).expect("send response");
        let send_err = move |e| ex.send(Err(CliError::from(e))).expect("send err");
        let hc = Self::build_https_client()?;
        rt::run(rt::lazy(move || hc.request(req).and_then(concat_body).map(send_res).map_err(send_err)));
        rx.recv().expect("recv response")
    }

    fn get_contents_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::Value>, CliError> {
        let req = self.build_page_request(url, page)?;
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, CliError> {
        match self.load_contents_from_cache(url) {
            Ok((metadata, cache_contents)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_contents_from_url(url) {
                            Ok(contents_from_url) => Ok(contents_from_url),
                            Err(_) => Ok(cache_contents),
                        }
                    } else {
                        Ok(cache_contents)
                    }
                }
                Err(_) => Ok(cache_contents),
            },
            Err(_) => self.get_contents_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let contents = self.get_contents(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&contents)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&contents)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&contents)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_rate_limit(&self) -> Result<RateLimit, CliError> {
        let url = format!("{}/rate_limit", self.conf.endpoint);
        let req = self.build_request(&url)?;
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    #[allow(dead_code)]
    pub fn print_rate_limit(&self) -> Result<(), CliError> {
        let rate_limit = self.get_rate_limit()?;
        println!("{:?}", rate_limit);
        Ok(())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Refactor<commit_after>use glob::glob;
use hyper::client::HttpConnector;
use hyper::rt::{self, Future, Stream};
use hyper::{header, Body, Chunk, Client, Request, Response};
use hyper_tls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::sync::mpsc;
use structs::{CliError, Config, Member, PublicKey, RateLimit, Repo, Sector, SectorGroup, Team};

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_contents_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut contents = String::new();
        f.read_to_string(&mut contents)?;
        Ok((metadata, contents))
    }

    fn store_contents_to_cache(&self, url: &str, contents: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_contents_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let contents = serde_json::ser::to_string(&all_contents)?;
        self.store_contents_to_cache(url, &contents)?;
        Ok(contents)
    }

    fn build_request(&self, url: &str) -> Result<Request<Body>, CliError> {
        let token = String::from("token ") + &self.conf.token;
        Request::get(url).header(header::AUTHORIZATION, token.as_str())
                         .header(header::USER_AGENT, "sectora")
                         .body(Body::empty())
                         .map_err(CliError::from)
    }

    fn build_page_request(&self, url: &str, page: u64) -> Result<Request<Body>, CliError> {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn build_https_client() -> Result<Client<HttpsConnector<HttpConnector>>, CliError> {
        Ok(Client::builder().build(HttpsConnector::new(4)?))
    }

    fn run_request(&self, req: Request<Body>) -> Result<Chunk, CliError> {
        let concat_body = |res: Response<Body>| res.into_body().concat2();
        let (tx, rx) = mpsc::sync_channel(1);
        let ex = tx.clone();
        let send_res = move |r| tx.send(Ok(r)).expect("send response");
        let send_err = move |e| ex.send(Err(CliError::from(e))).expect("send err");
        let hc = Self::build_https_client()?;
        rt::run(rt::lazy(move || hc.request(req).and_then(concat_body).map(send_res).map_err(send_err)));
        rx.recv().expect("recv response")
    }

    fn get_contents_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::Value>, CliError> {
        let req = self.build_page_request(url, page)?;
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    fn get_contents(&self, url: &str) -> Result<String, CliError> {
        match self.load_contents_from_cache(url) {
            Ok((metadata, cache_contents)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_contents_from_url(url) {
                            Ok(contents_from_url) => Ok(contents_from_url),
                            Err(_) => Ok(cache_contents),
                        }
                    } else {
                        Ok(cache_contents)
                    }
                }
                Err(_) => Ok(cache_contents),
            },
            Err(_) => self.get_contents_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let contents = self.get_contents(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&contents)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&contents)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&contents)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_rate_limit(&self) -> Result<RateLimit, CliError> {
        let url = format!("{}/rate_limit", self.conf.endpoint);
        let req = self.build_request(&url)?;
        self.run_request(req).and_then(|body| serde_json::from_slice(&body).map_err(CliError::from))
    }

    #[allow(dead_code)]
    pub fn print_rate_limit(&self) -> Result<(), CliError> {
        let rate_limit = self.get_rate_limit()?;
        println!("{:?}", rate_limit);
        Ok(())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate futures;
extern crate test;

use futures::{Async, Poll, AsyncSink};
use futures::executor;
use futures::executor::{Notify, NotifyHandle};

use futures::sink::Sink;
use futures::stream::Stream;

use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::channel;
use futures::sync::mpsc::Sender;
use futures::sync::mpsc::UnboundedSender;

use test::Bencher;

fn notify_noop() -> NotifyHandle {
    struct Noop;

    impl Notify for Noop {
        fn notify(&self, _id: usize) {}
    }

    const NOOP : &'static Noop = &Noop;

    NotifyHandle::from(NOOP)
}

/// Single producer, single consumer
#[bench]
fn unbounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = unbounded();

        let mut rx = executor::spawn(rx);

        // 1000 iterations to avoid measuring overhead of initialization
        // Result should be divided by 1000
        for i in 0..1000 {

            // Poll, not ready, park
            assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));

            UnboundedSender::send(&tx, i).unwrap();

            // Now poll ready
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn unbounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = unbounded();

        let mut rx = executor::spawn(rx);

        let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();

        // 1000 send/recv operations total, result should be divided by 1000
        for _ in 0..10 {
            for i in 0..tx.len() {
                assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));

                UnboundedSender::send(&tx[i], i).unwrap();

                assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
            }
        }
    })
}

#[bench]
fn unbounded_uncontended(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();

        for i in 0..1000 {
            UnboundedSender::send(&tx, i).expect("send");
            // No need to create a task, because poll is not going to park.
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll());
        }
    })
}

/// A Stream that continuously sends incrementing number of the queue
struct TestSender {
    tx: Sender<u32>,
    last: u32, // Last number sent
}

// Could be a Future, it doesn't matter
impl Stream for TestSender {
    type Item = u32;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.tx.start_send(self.last + 1) {
            Err(_) => panic!(),
            Ok(AsyncSink::Ready) => {
                self.last += 1;
                assert_eq!(Ok(Async::Ready(())), self.tx.poll_complete());
                Ok(Async::Ready(Some(self.last)))
            }
            Ok(AsyncSink::NotReady(_)) => {
                Ok(Async::NotReady)
            }
        }
    }
}

/// Single producers, single consumer
#[bench]
fn bounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = channel(0);

        let mut tx = executor::spawn(TestSender {
            tx: tx,
            last: 0,
        });

        let mut rx = executor::spawn(rx);

        for i in 0..1000 {
            assert_eq!(Ok(Async::Ready(Some(i + 1))), tx.poll_stream_notify(&notify_noop(), 1));
            assert_eq!(Ok(Async::NotReady), tx.poll_stream_notify(&notify_noop(), 1));
            assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn bounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        // Each sender can send one item after specified capacity
        let (tx, rx) = channel(0);

        let mut tx: Vec<_> = (0..100).map(|_| {
            executor::spawn(TestSender {
                tx: tx.clone(),
                last: 0
            })
        }).collect();

        let mut rx = executor::spawn(rx);

        for i in 0..10 {
            for j in 0..tx.len() {
                // Send an item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), tx[j].poll_stream_notify(&notify_noop(), 1));
                // Then block
                assert_eq!(Ok(Async::NotReady), tx[j].poll_stream_notify(&notify_noop(), 1));
                // Recv the item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
            }
        }
    })
}
<commit_msg>remove usage of deprecated API in benches<commit_after>#![feature(test)]

extern crate futures;
extern crate test;

use futures::{Async, Poll, AsyncSink};
use futures::executor;
use futures::executor::{Notify, NotifyHandle};

use futures::sink::Sink;
use futures::stream::Stream;

use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::channel;
use futures::sync::mpsc::Sender;
use futures::sync::mpsc::UnboundedSender;

use test::Bencher;

fn notify_noop() -> NotifyHandle {
    struct Noop;

    impl Notify for Noop {
        fn notify(&self, _id: usize) {}
    }

    const NOOP : &'static Noop = &Noop;

    NotifyHandle::from(NOOP)
}

/// Single producer, single consumer
#[bench]
fn unbounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = unbounded();

        let mut rx = executor::spawn(rx);

        // 1000 iterations to avoid measuring overhead of initialization
        // Result should be divided by 1000
        for i in 0..1000 {

            // Poll, not ready, park
            assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));

            UnboundedSender::unbounded_send(&tx, i).unwrap();

            // Now poll ready
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn unbounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = unbounded();

        let mut rx = executor::spawn(rx);

        let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();

        // 1000 send/recv operations total, result should be divided by 1000
        for _ in 0..10 {
            for i in 0..tx.len() {
                assert_eq!(Ok(Async::NotReady), rx.poll_stream_notify(&notify_noop(), 1));

                UnboundedSender::unbounded_send(&tx[i], i).unwrap();

                assert_eq!(Ok(Async::Ready(Some(i))), rx.poll_stream_notify(&notify_noop(), 1));
            }
        }
    })
}

#[bench]
fn unbounded_uncontended(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();

        for i in 0..1000 {
            UnboundedSender::unbounded_send(&tx, i).expect("send");
            // No need to create a task, because poll is not going to park.
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll());
        }
    })
}

/// A Stream that continuously sends incrementing number of the queue
struct TestSender {
    tx: Sender<u32>,
    last: u32, // Last number sent
}

// Could be a Future, it doesn't matter
impl Stream for TestSender {
    type Item = u32;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.tx.start_send(self.last + 1) {
            Err(_) => panic!(),
            Ok(AsyncSink::Ready) => {
                self.last += 1;
                assert_eq!(Ok(Async::Ready(())), self.tx.poll_complete());
                Ok(Async::Ready(Some(self.last)))
            }
            Ok(AsyncSink::NotReady(_)) => {
                Ok(Async::NotReady)
            }
        }
    }
}

/// Single producers, single consumer
#[bench]
fn bounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, rx) = channel(0);

        let mut tx = executor::spawn(TestSender {
            tx: tx,
            last: 0,
        });

        let mut rx = executor::spawn(rx);

        for i in 0..1000 {
            assert_eq!(Ok(Async::Ready(Some(i + 1))), tx.poll_stream_notify(&notify_noop(), 1));
            assert_eq!(Ok(Async::NotReady), tx.poll_stream_notify(&notify_noop(), 1));
            assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn bounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        // Each sender can send one item after specified capacity
        let (tx, rx) = channel(0);

        let mut tx: Vec<_> = (0..100).map(|_| {
            executor::spawn(TestSender {
                tx: tx.clone(),
                last: 0
            })
        }).collect();

        let mut rx = executor::spawn(rx);

        for i in 0..10 {
            for j in 0..tx.len() {
                // Send an item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), tx[j].poll_stream_notify(&notify_noop(), 1));
                // Then block
                assert_eq!(Ok(Async::NotReady), tx[j].poll_stream_notify(&notify_noop(), 1));
                // Recv the item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll_stream_notify(&notify_noop(), 1));
            }
        }
    })
}
<|endoftext|>


<commit_before>use ra_db::{FileId, SourceDatabase};
use ra_syntax::{
    SyntaxNode, AstNode, SmolStr, TextRange, AstPtr,
    SyntaxKind::{self, NAME},
    ast::{self, DocCommentsOwner},
    algo::visit::{visitor, Visitor},
};
use hir::{ModuleSource, FieldSource, ImplItem};

use crate::{FileSymbol, db::RootDatabase};
use super::description::Description;

/// `NavigationTarget` represents and element in the editor's UI which you can
/// click on to navigate to a particular piece of code.
///
/// Typically, a `NavigationTarget` corresponds to some element in the source
/// code, like a function or a struct, but this is not strictly required.
#[derive(Debug, Clone)]
pub struct NavigationTarget {
    file_id: FileId,
    name: SmolStr,
    kind: SyntaxKind,
    full_range: TextRange,
    focus_range: Option<TextRange>,
    container_name: Option<SmolStr>,
    description: Option<String>,
    docs: Option<String>,
}

impl NavigationTarget {
    /// When `focus_range` is specified, returns it. otherwise
    /// returns `full_range`
    pub fn range(&self) -> TextRange {
        self.focus_range.unwrap_or(self.full_range)
    }

    pub fn name(&self) -> &SmolStr {
        &self.name
    }

    pub fn container_name(&self) -> Option<&SmolStr> {
        self.container_name.as_ref()
    }

    pub fn kind(&self) -> SyntaxKind {
        self.kind
    }

    pub fn file_id(&self) -> FileId {
        self.file_id
    }

    pub fn full_range(&self) -> TextRange {
        self.full_range
    }

    pub fn docs(&self) -> Option<String> {
        self.docs.clone()
    }

    pub fn description(&self) -> Option<String> {
        self.description.clone()
    }

    /// A "most interesting" range withing the `full_range`.
    ///
    /// Typically, `full_range` is the whole syntax node,
    /// including doc comments, and `focus_range` is the range of the identifier.
    pub fn focus_range(&self) -> Option<TextRange> {
        self.focus_range
    }

    pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget {
        NavigationTarget::from_named(file_id, pat, None, None)
    }

    pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
        let file = db.parse(symbol.file_id).tree;
        let node = symbol.ptr.to_node(file.syntax()).to_owned();

        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            full_range: symbol.ptr.range(),
            focus_range: symbol.name_range,
            container_name: symbol.container_name.clone(),
            description: description_from_symbol(&node),
            docs: docs_from_symbol(db, &symbol),
        }
    }

    pub(crate) fn from_pat(
        db: &RootDatabase,
        file_id: FileId,
        pat: AstPtr<ast::Pat>,
    ) -> NavigationTarget {
        let file = db.parse(file_id).tree;
        let (name, full_range) = match pat.to_node(file.syntax()).kind() {
            ast::PatKind::BindPat(pat) => return NavigationTarget::from_bind_pat(file_id, &pat),
            _ => ("_".into(), pat.syntax_node_ptr().range()),
        };

        NavigationTarget {
            file_id,
            name,
            full_range,
            focus_range: None,
            kind: NAME,
            container_name: None,
            description: None, //< No documentation for Description
            docs: None,        //< No documentation for Pattern
        }
    }

    pub(crate) fn from_self_param(
        file_id: FileId,
        par: AstPtr<ast::SelfParam>,
    ) -> NavigationTarget {
        let (name, full_range) = ("self".into(), par.syntax_node_ptr().range());

        NavigationTarget {
            file_id,
            name,
            full_range,
            focus_range: None,
            kind: NAME,
            container_name: None,
            description: None, //< No document node for SelfParam
            docs: None,        //< No document node for SelfParam
        }
    }

    pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
        let (file_id, source) = module.definition_source(db);
        let file_id = file_id.as_original_file();
        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
        match source {
            ModuleSource::SourceFile(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None)
            }
            ModuleSource::Module(node) => NavigationTarget::from_syntax(
                file_id,
                name,
                None,
                node.syntax(),
                node.doc_comment_text(),
                node.description(),
            ),
        }
    }

    pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
        if let Some((file_id, source)) = module.declaration_source(db) {
            let file_id = file_id.as_original_file();
            return NavigationTarget::from_syntax(
                file_id,
                name,
                None,
                source.syntax(),
                source.doc_comment_text(),
                source.description(),
            );
        }
        NavigationTarget::from_module(db, module)
    }

    pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget {
        let (file_id, fn_def) = func.source(db);
        NavigationTarget::from_named(
            file_id.original_file(db),
            &*fn_def,
            fn_def.doc_comment_text(),
            fn_def.description(),
        )
    }

    pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
        let (file_id, field) = field.source(db);
        let file_id = file_id.original_file(db);
        match field {
            FieldSource::Named(it) => {
                NavigationTarget::from_named(file_id, &*it, it.doc_comment_text(), it.description())
            }
            FieldSource::Pos(it) => {
                NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None)
            }
        }
    }

    pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget {
        match adt_def {
            hir::AdtDef::Struct(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::AdtDef::Union(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::AdtDef::Enum(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
        }
    }

    pub(crate) fn from_def(
        db: &RootDatabase,
        module_def: hir::ModuleDef,
    ) -> Option<NavigationTarget> {
        let nav = match module_def {
            hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module),
            hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func),
            hir::ModuleDef::Struct(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Union(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Const(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Static(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Enum(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::EnumVariant(var) => {
                let (file_id, node) = var.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Trait(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::TypeAlias(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::BuiltinType(..) => {
                return None;
            }
        };
        Some(nav)
    }

    pub(crate) fn from_impl_block(
        db: &RootDatabase,
        impl_block: hir::ImplBlock,
    ) -> NavigationTarget {
        let (file_id, node) = impl_block.source(db);
        NavigationTarget::from_syntax(
            file_id.as_original_file(),
            "impl".into(),
            None,
            node.syntax(),
            None,
            None,
        )
    }

    pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget {
        match impl_item {
            ImplItem::Method(f) => NavigationTarget::from_function(db, f),
            ImplItem::Const(c) => {
                let (file_id, node) = c.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            ImplItem::TypeAlias(a) => {
                let (file_id, node) = a.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
        }
    }

    pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
        let (file_id, node) = macro_call.source(db);
        log::debug!("nav target {}", node.syntax().debug_dump());
        NavigationTarget::from_named(
            file_id.original_file(db),
            &*node,
            node.doc_comment_text(),
            None,
        )
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        let mut buf = format!(
            "{} {:?} {:?} {:?}",
            self.name(),
            self.kind(),
            self.file_id(),
            self.full_range()
        );
        if let Some(focus_range) = self.focus_range() {
            buf.push_str(&format!(" {:?}", focus_range))
        }
        if let Some(container_name) = self.container_name() {
            buf.push_str(&format!(" {}", container_name))
        }
        buf
    }

    /// Allows `NavigationTarget` to be created from a `NameOwner`
    pub(crate) fn from_named(
        file_id: FileId,
        node: &impl ast::NameOwner,
        docs: Option<String>,
        description: Option<String>,
    ) -> NavigationTarget {
        //FIXME: use `_` instead of empty string
        let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
        let focus_range = node.name().map(|it| it.syntax().range());
        NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description)
    }

    fn from_syntax(
        file_id: FileId,
        name: SmolStr,
        focus_range: Option<TextRange>,
        node: &SyntaxNode,
        docs: Option<String>,
        description: Option<String>,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name,
            kind: node.kind(),
            full_range: node.range(),
            focus_range,
            // ptr: Some(LocalSyntaxPtr::new(node)),
            container_name: None,
            description,
            docs,
        }
    }
}

fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
    let file = db.parse(symbol.file_id).tree;
    let node = symbol.ptr.to_node(file.syntax()).to_owned();

    fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> {
        node.doc_comment_text()
    }

    visitor()
        .visit(doc_comments::<ast::FnDef>)
        .visit(doc_comments::<ast::StructDef>)
        .visit(doc_comments::<ast::EnumDef>)
        .visit(doc_comments::<ast::TraitDef>)
        .visit(doc_comments::<ast::Module>)
        .visit(doc_comments::<ast::TypeAliasDef>)
        .visit(doc_comments::<ast::ConstDef>)
        .visit(doc_comments::<ast::StaticDef>)
        .visit(doc_comments::<ast::NamedFieldDef>)
        .visit(doc_comments::<ast::EnumVariant>)
        .visit(doc_comments::<ast::MacroCall>)
        .accept(&node)?
}

/// Get a description of a symbol.
///
/// e.g. `struct Name`, `enum Name`, `fn Name`
fn description_from_symbol(node: &SyntaxNode) -> Option<String> {
    // FIXME: After type inference is done, add type information to improve the output

    visitor()
        .visit(|node: &ast::FnDef| node.description())
        .visit(|node: &ast::StructDef| node.description())
        .visit(|node: &ast::EnumDef| node.description())
        .visit(|node: &ast::TraitDef| node.description())
        .visit(|node: &ast::Module| node.description())
        .visit(|node: &ast::TypeAliasDef| node.description())
        .visit(|node: &ast::ConstDef| node.description())
        .visit(|node: &ast::StaticDef| node.description())
        .visit(|node: &ast::NamedFieldDef| node.description())
        .visit(|node: &ast::EnumVariant| node.description())
        .accept(&node)?
}
<commit_msg>Make description_from_symbol depends on symbol<commit_after>use ra_db::{FileId, SourceDatabase};
use ra_syntax::{
    SyntaxNode, AstNode, SmolStr, TextRange, AstPtr,
    SyntaxKind::{self, NAME},
    ast::{self, DocCommentsOwner},
    algo::visit::{visitor, Visitor},
};
use hir::{ModuleSource, FieldSource, ImplItem};

use crate::{FileSymbol, db::RootDatabase};
use super::description::Description;

/// `NavigationTarget` represents and element in the editor's UI which you can
/// click on to navigate to a particular piece of code.
///
/// Typically, a `NavigationTarget` corresponds to some element in the source
/// code, like a function or a struct, but this is not strictly required.
#[derive(Debug, Clone)]
pub struct NavigationTarget {
    file_id: FileId,
    name: SmolStr,
    kind: SyntaxKind,
    full_range: TextRange,
    focus_range: Option<TextRange>,
    container_name: Option<SmolStr>,
    description: Option<String>,
    docs: Option<String>,
}

impl NavigationTarget {
    /// When `focus_range` is specified, returns it. otherwise
    /// returns `full_range`
    pub fn range(&self) -> TextRange {
        self.focus_range.unwrap_or(self.full_range)
    }

    pub fn name(&self) -> &SmolStr {
        &self.name
    }

    pub fn container_name(&self) -> Option<&SmolStr> {
        self.container_name.as_ref()
    }

    pub fn kind(&self) -> SyntaxKind {
        self.kind
    }

    pub fn file_id(&self) -> FileId {
        self.file_id
    }

    pub fn full_range(&self) -> TextRange {
        self.full_range
    }

    pub fn docs(&self) -> Option<String> {
        self.docs.clone()
    }

    pub fn description(&self) -> Option<String> {
        self.description.clone()
    }

    /// A "most interesting" range withing the `full_range`.
    ///
    /// Typically, `full_range` is the whole syntax node,
    /// including doc comments, and `focus_range` is the range of the identifier.
    pub fn focus_range(&self) -> Option<TextRange> {
        self.focus_range
    }

    pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget {
        NavigationTarget::from_named(file_id, pat, None, None)
    }

    pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            full_range: symbol.ptr.range(),
            focus_range: symbol.name_range,
            container_name: symbol.container_name.clone(),
            description: description_from_symbol(db, &symbol),
            docs: docs_from_symbol(db, &symbol),
        }
    }

    pub(crate) fn from_pat(
        db: &RootDatabase,
        file_id: FileId,
        pat: AstPtr<ast::Pat>,
    ) -> NavigationTarget {
        let file = db.parse(file_id).tree;
        let (name, full_range) = match pat.to_node(file.syntax()).kind() {
            ast::PatKind::BindPat(pat) => return NavigationTarget::from_bind_pat(file_id, &pat),
            _ => ("_".into(), pat.syntax_node_ptr().range()),
        };

        NavigationTarget {
            file_id,
            name,
            full_range,
            focus_range: None,
            kind: NAME,
            container_name: None,
            description: None, //< No documentation for Description
            docs: None,        //< No documentation for Pattern
        }
    }

    pub(crate) fn from_self_param(
        file_id: FileId,
        par: AstPtr<ast::SelfParam>,
    ) -> NavigationTarget {
        let (name, full_range) = ("self".into(), par.syntax_node_ptr().range());

        NavigationTarget {
            file_id,
            name,
            full_range,
            focus_range: None,
            kind: NAME,
            container_name: None,
            description: None, //< No document node for SelfParam
            docs: None,        //< No document node for SelfParam
        }
    }

    pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
        let (file_id, source) = module.definition_source(db);
        let file_id = file_id.as_original_file();
        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
        match source {
            ModuleSource::SourceFile(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None)
            }
            ModuleSource::Module(node) => NavigationTarget::from_syntax(
                file_id,
                name,
                None,
                node.syntax(),
                node.doc_comment_text(),
                node.description(),
            ),
        }
    }

    pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
        if let Some((file_id, source)) = module.declaration_source(db) {
            let file_id = file_id.as_original_file();
            return NavigationTarget::from_syntax(
                file_id,
                name,
                None,
                source.syntax(),
                source.doc_comment_text(),
                source.description(),
            );
        }
        NavigationTarget::from_module(db, module)
    }

    pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget {
        let (file_id, fn_def) = func.source(db);
        NavigationTarget::from_named(
            file_id.original_file(db),
            &*fn_def,
            fn_def.doc_comment_text(),
            fn_def.description(),
        )
    }

    pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
        let (file_id, field) = field.source(db);
        let file_id = file_id.original_file(db);
        match field {
            FieldSource::Named(it) => {
                NavigationTarget::from_named(file_id, &*it, it.doc_comment_text(), it.description())
            }
            FieldSource::Pos(it) => {
                NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None)
            }
        }
    }

    pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget {
        match adt_def {
            hir::AdtDef::Struct(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::AdtDef::Union(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::AdtDef::Enum(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
        }
    }

    pub(crate) fn from_def(
        db: &RootDatabase,
        module_def: hir::ModuleDef,
    ) -> Option<NavigationTarget> {
        let nav = match module_def {
            hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module),
            hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func),
            hir::ModuleDef::Struct(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Union(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Const(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Static(s) => {
                let (file_id, node) = s.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Enum(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::EnumVariant(var) => {
                let (file_id, node) = var.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::Trait(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::TypeAlias(e) => {
                let (file_id, node) = e.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            hir::ModuleDef::BuiltinType(..) => {
                return None;
            }
        };
        Some(nav)
    }

    pub(crate) fn from_impl_block(
        db: &RootDatabase,
        impl_block: hir::ImplBlock,
    ) -> NavigationTarget {
        let (file_id, node) = impl_block.source(db);
        NavigationTarget::from_syntax(
            file_id.as_original_file(),
            "impl".into(),
            None,
            node.syntax(),
            None,
            None,
        )
    }

    pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget {
        match impl_item {
            ImplItem::Method(f) => NavigationTarget::from_function(db, f),
            ImplItem::Const(c) => {
                let (file_id, node) = c.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
            ImplItem::TypeAlias(a) => {
                let (file_id, node) = a.source(db);
                NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                    node.doc_comment_text(),
                    node.description(),
                )
            }
        }
    }

    pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
        let (file_id, node) = macro_call.source(db);
        log::debug!("nav target {}", node.syntax().debug_dump());
        NavigationTarget::from_named(
            file_id.original_file(db),
            &*node,
            node.doc_comment_text(),
            None,
        )
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        let mut buf = format!(
            "{} {:?} {:?} {:?}",
            self.name(),
            self.kind(),
            self.file_id(),
            self.full_range()
        );
        if let Some(focus_range) = self.focus_range() {
            buf.push_str(&format!(" {:?}", focus_range))
        }
        if let Some(container_name) = self.container_name() {
            buf.push_str(&format!(" {}", container_name))
        }
        buf
    }

    /// Allows `NavigationTarget` to be created from a `NameOwner`
    pub(crate) fn from_named(
        file_id: FileId,
        node: &impl ast::NameOwner,
        docs: Option<String>,
        description: Option<String>,
    ) -> NavigationTarget {
        //FIXME: use `_` instead of empty string
        let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
        let focus_range = node.name().map(|it| it.syntax().range());
        NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description)
    }

    fn from_syntax(
        file_id: FileId,
        name: SmolStr,
        focus_range: Option<TextRange>,
        node: &SyntaxNode,
        docs: Option<String>,
        description: Option<String>,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name,
            kind: node.kind(),
            full_range: node.range(),
            focus_range,
            // ptr: Some(LocalSyntaxPtr::new(node)),
            container_name: None,
            description,
            docs,
        }
    }
}

fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
    let file = db.parse(symbol.file_id).tree;
    let node = symbol.ptr.to_node(file.syntax()).to_owned();

    fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> {
        node.doc_comment_text()
    }

    visitor()
        .visit(doc_comments::<ast::FnDef>)
        .visit(doc_comments::<ast::StructDef>)
        .visit(doc_comments::<ast::EnumDef>)
        .visit(doc_comments::<ast::TraitDef>)
        .visit(doc_comments::<ast::Module>)
        .visit(doc_comments::<ast::TypeAliasDef>)
        .visit(doc_comments::<ast::ConstDef>)
        .visit(doc_comments::<ast::StaticDef>)
        .visit(doc_comments::<ast::NamedFieldDef>)
        .visit(doc_comments::<ast::EnumVariant>)
        .visit(doc_comments::<ast::MacroCall>)
        .accept(&node)?
}

/// Get a description of a symbol.
///
/// e.g. `struct Name`, `enum Name`, `fn Name`
fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
    let file = db.parse(symbol.file_id).tree;
    let node = symbol.ptr.to_node(file.syntax()).to_owned();

    // FIXME: After type inference is done, add type information to improve the output

    visitor()
        .visit(|node: &ast::FnDef| node.description())
        .visit(|node: &ast::StructDef| node.description())
        .visit(|node: &ast::EnumDef| node.description())
        .visit(|node: &ast::TraitDef| node.description())
        .visit(|node: &ast::Module| node.description())
        .visit(|node: &ast::TypeAliasDef| node.description())
        .visit(|node: &ast::ConstDef| node.description())
        .visit(|node: &ast::StaticDef| node.description())
        .visit(|node: &ast::NamedFieldDef| node.description())
        .visit(|node: &ast::EnumVariant| node.description())
        .accept(&node)?
}
<|endoftext|>