<commit_before>use num::integer::gcd;

fn main() {
    // Compute the totient of the first 25 natural integers
    println!("N\t phi(n)\t Prime");
    for n in 1..26 {
        let phi_n = phi(n);
        println!("{}\t {}\t {:?}", n, phi_n, phi_n == n - 1);
    }

    // Compute the number of prime numbers for various steps
    [1, 100, 1000, 10000, 100000]
        .windows(2)
        .scan(0, |acc, tuple| {
            *acc += (tuple[0]..=tuple[1]).filter(is_prime).count();
            Some((tuple[1], *acc))
        })
        .for_each(|x| println!("Until {}: {} prime numbers", x.0, x.1));
}

fn is_prime(n: &usize) -> bool {
    phi(*n) == *n - 1
}

fn phi(n: usize) -> usize {
    (1..=n).filter(|&x| gcd(n, x) == 1).count()
}
<commit_msg>Added proper tests<commit_after>use num::integer::gcd;

fn main() {
    // Compute the totient of the first 25 natural integers
    println!("N\t phi(n)\t Prime");
    for n in 1..26 {
        let phi_n = phi(n);
        println!("{}\t {}\t {:?}", n, phi_n, phi_n == n - 1);
    }

    // Compute the number of prime numbers for various steps
    [1, 100, 1000, 10000, 100000]
        .windows(2)
        .scan(0, |acc, window| {
            let (lower, upper) = (window[0], window[1]);
            *acc += (lower..=upper).filter(is_prime).count();
            Some((upper, *acc))
        })
        .for_each(|x| println!("Until {}: {} prime numbers", x.0, x.1));
}

fn is_prime(n: &usize) -> bool {
    phi(*n) == *n - 1
}

fn phi(n: usize) -> usize {
    (1..=n).filter(|&x| gcd(n, x) == 1).count()
}

#[cfg(test)]
mod tests {
    use super::{is_prime, phi};

    #[test]
    fn test_totient_primes() {
        let results = vec![
            (1, 1, false),
            (2, 1, true),
            (3, 2, true),
            (4, 2, false),
            (5, 4, true),
            (6, 2, false),
            (7, 6, true),
            (8, 4, false),
            (9, 6, false),
            (10, 4, false),
            (11, 10, true),
            (12, 4, false),
            (13, 12, true),
            (14, 6, false),
            (15, 8, false),
            (16, 8, false),
            (17, 16, true),
            (18, 6, false),
            (19, 18, true),
            (20, 8, false),
            (21, 12, false),
            (22, 10, false),
            (23, 22, true),
            (24, 8, false),
            (25, 20, false),
        ];
        for n in 1..26 {
            let phi_n = phi(n);
            assert_eq!((n, phi_n, phi_n == n - 1), results[n - 1]);
        }
    }

    #[test]
    #[ignore]
    fn test_totient_prime_list() {
        let results: Vec<usize> = [1, 100, 1000, 10000, 100000]
            .windows(2)
            .scan(0, |acc, window| {
                let (lower, upper) = (window[0], window[1]);
                *acc += (lower..=upper).filter(is_prime).count();
                Some(*acc)
            })
            .collect();

        assert_eq!(results, vec![25, 168, 1229, 9592]);
    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use draw::add_clipping_rect;
use drawing_ctx::{self, RsvgDrawingCtx};
use float_eq_cairo::ApproxEqCairo;
use node::RsvgNode;
use state::ComputedValues;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox,
}

pub fn draw_in_viewport<F>(
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    affine: cairo::Matrix,
    draw_ctx: *mut RsvgDrawingCtx,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(
        &mut ctx,
        vx,
        vy,
        vw,
        vh,
        clip_mode,
        do_clip,
        vbox,
        preserve_aspect_ratio,
        node,
        values,
        affine,
        clipping,
        draw_fn,
    );
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self);
    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool);
    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *mut RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool) {
        drawing_ctx::push_discrete_layer(self.0, values, clipping);
    }

    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool) {
        drawing_ctx::pop_discrete_layer(self.0, node, values, clipping);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::get_cairo_context(self.0).set_matrix(affine);
    }
}

fn in_viewport<F>(
    ctx: &mut ViewportCtx,
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    mut affine: cairo::Matrix,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if vw.approx_eq_cairo(&0.0) || vh.approx_eq_cairo(&0.0) {
        return;
    }

    let old_affine = affine;

    ctx.push_discrete_layer(values, clipping);

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if vbox.0.width.approx_eq_cairo(&0.0) || vbox.0.height.approx_eq_cairo(&0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }

        ctx.push_view_box(vbox.0.width, vbox.0.height);

        let (x, y, w, h) =
            preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height, vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        ctx.set_affine(affine);

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        ctx.push_view_box(vw, vh);

        affine.translate(vx, vy);
        ctx.set_affine(affine);
    }

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        ctx.set_affine(old_affine);
        ctx.add_clipping_rect(vx, vy, vw, vh);
        ctx.set_affine(affine);
    }

    draw_fn();

    ctx.pop_view_box();
    ctx.pop_discrete_layer(node, values, clipping);
}

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

    use std::ptr;
    use std::rc::Rc;

    use handle::RsvgHandle;
    use node::{Node, NodeResult, NodeTrait, NodeType};
    use parsers::Parse;
    use property_bag::PropertyBag;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
            Ok(())
        }
    }
    #[derive(Default, PartialEq)]
    struct Ctx {
        pub view_box_size: Option<(f64, f64)>,
        pub clipping_rect: Option<(f64, f64, f64, f64)>,
        pub affine: Option<cairo::Matrix>,

        pub expected_view_box_size: Option<(f64, f64)>,
        pub expected_clipping_rect: Option<(f64, f64, f64, f64)>,
        pub expected_affine: Option<cairo::Matrix>,
    }

    impl ViewportCtx for Ctx {
        fn push_view_box(&mut self, width: f64, height: f64) {
            self.view_box_size = Some((width, height));
        }

        fn pop_view_box(&mut self) {}

        fn push_discrete_layer(&mut self, _values: &ComputedValues, _clipping: bool) {}

        fn pop_discrete_layer(
            &mut self,
            _node: &RsvgNode,
            _values: &ComputedValues,
            _clipping: bool,
        ) {
        }

        fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
            self.clipping_rect = Some((x, y, w, h));
        }

        fn set_affine(&mut self, affine: cairo::Matrix) {
            self.affine = Some(affine);
        }
    }

    fn call_in_viewport(
        vx: f64,
        vy: f64,
        vw: f64,
        vh: f64,
        clip_mode: ClipMode,
        do_clip: bool,
        vbox: Option<ViewBox>,
        preserve_aspect_ratio: AspectRatio,
        affine: cairo::Matrix,
        ctx: &mut Ctx,
    ) {
        let node = Rc::new(Node::new(
            NodeType::Path,
            None,
            None,
            None,
            ptr::null_mut(),
            Box::new(TestNodeImpl {}),
        ));

        in_viewport(
            ctx,
            vx,
            vy,
            vw,
            vh,
            clip_mode,
            do_clip,
            vbox,
            preserve_aspect_ratio,
            &node,
            &ComputedValues::default(),
            affine,
            false,
            || (),
        );

        assert_eq!(ctx.view_box_size, ctx.expected_view_box_size);
        assert_eq!(ctx.clipping_rect, ctx.expected_clipping_rect);
        assert_eq!(ctx.affine, ctx.expected_affine);
    }

    #[test]
    fn clip_to_viewport() {
        let mut affine = cairo::Matrix::identity();
        affine.scale(0.25, 0.25);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((40.0, 40.0)),
            expected_clipping_rect: Some((10.0, 10.0, 10.0, 10.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            10.0,
            10.0,
            ClipMode::ClipToViewport,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 40.0,
                y: 40.0,
                width: 40.0,
                height: 40.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }

    #[test]
    fn clip_to_vbox() {
        let mut affine = cairo::Matrix::identity();
        affine.translate(10.0, 10.0);
        affine.scale(0.40, 0.40);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((0.0, 0.0, 50.0, 50.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            20.0,
            20.0,
            ClipMode::ClipToVbox,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 50.0,
                height: 50.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }
}
<commit_msg>viewport.rs: Simplify setting the clip rectangle for ClipToViewport<commit_after>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use draw::add_clipping_rect;
use drawing_ctx::{self, RsvgDrawingCtx};
use float_eq_cairo::ApproxEqCairo;
use node::RsvgNode;
use state::ComputedValues;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox,
}

pub fn draw_in_viewport<F>(
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    affine: cairo::Matrix,
    draw_ctx: *mut RsvgDrawingCtx,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(
        &mut ctx,
        vx,
        vy,
        vw,
        vh,
        clip_mode,
        do_clip,
        vbox,
        preserve_aspect_ratio,
        node,
        values,
        affine,
        clipping,
        draw_fn,
    );
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self);
    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool);
    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *mut RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool) {
        drawing_ctx::push_discrete_layer(self.0, values, clipping);
    }

    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool) {
        drawing_ctx::pop_discrete_layer(self.0, node, values, clipping);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::get_cairo_context(self.0).set_matrix(affine);
    }
}

fn in_viewport<F>(
    ctx: &mut ViewportCtx,
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    mut affine: cairo::Matrix,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if vw.approx_eq_cairo(&0.0) || vh.approx_eq_cairo(&0.0) {
        return;
    }

    ctx.push_discrete_layer(values, clipping);

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        ctx.set_affine(affine);
        ctx.add_clipping_rect(vx, vy, vw, vh);
    }

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if vbox.0.width.approx_eq_cairo(&0.0) || vbox.0.height.approx_eq_cairo(&0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }

        ctx.push_view_box(vbox.0.width, vbox.0.height);

        let (x, y, w, h) =
            preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height, vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        ctx.set_affine(affine);

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        ctx.push_view_box(vw, vh);

        affine.translate(vx, vy);
        ctx.set_affine(affine);
    }

    draw_fn();

    ctx.pop_view_box();
    ctx.pop_discrete_layer(node, values, clipping);
}

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

    use std::ptr;
    use std::rc::Rc;

    use handle::RsvgHandle;
    use node::{Node, NodeResult, NodeTrait, NodeType};
    use parsers::Parse;
    use property_bag::PropertyBag;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
            Ok(())
        }
    }
    #[derive(Default, PartialEq)]
    struct Ctx {
        pub view_box_size: Option<(f64, f64)>,
        pub clipping_rect: Option<(f64, f64, f64, f64)>,
        pub affine: Option<cairo::Matrix>,

        pub expected_view_box_size: Option<(f64, f64)>,
        pub expected_clipping_rect: Option<(f64, f64, f64, f64)>,
        pub expected_affine: Option<cairo::Matrix>,
    }

    impl ViewportCtx for Ctx {
        fn push_view_box(&mut self, width: f64, height: f64) {
            self.view_box_size = Some((width, height));
        }

        fn pop_view_box(&mut self) {}

        fn push_discrete_layer(&mut self, _values: &ComputedValues, _clipping: bool) {}

        fn pop_discrete_layer(
            &mut self,
            _node: &RsvgNode,
            _values: &ComputedValues,
            _clipping: bool,
        ) {
        }

        fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
            self.clipping_rect = Some((x, y, w, h));
        }

        fn set_affine(&mut self, affine: cairo::Matrix) {
            self.affine = Some(affine);
        }
    }

    fn call_in_viewport(
        vx: f64,
        vy: f64,
        vw: f64,
        vh: f64,
        clip_mode: ClipMode,
        do_clip: bool,
        vbox: Option<ViewBox>,
        preserve_aspect_ratio: AspectRatio,
        affine: cairo::Matrix,
        ctx: &mut Ctx,
    ) {
        let node = Rc::new(Node::new(
            NodeType::Path,
            None,
            None,
            None,
            ptr::null_mut(),
            Box::new(TestNodeImpl {}),
        ));

        in_viewport(
            ctx,
            vx,
            vy,
            vw,
            vh,
            clip_mode,
            do_clip,
            vbox,
            preserve_aspect_ratio,
            &node,
            &ComputedValues::default(),
            affine,
            false,
            || (),
        );

        assert_eq!(ctx.view_box_size, ctx.expected_view_box_size);
        assert_eq!(ctx.clipping_rect, ctx.expected_clipping_rect);
        assert_eq!(ctx.affine, ctx.expected_affine);
    }

    #[test]
    fn clip_to_viewport() {
        let mut affine = cairo::Matrix::identity();
        affine.scale(0.25, 0.25);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((40.0, 40.0)),
            expected_clipping_rect: Some((10.0, 10.0, 10.0, 10.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            10.0,
            10.0,
            ClipMode::ClipToViewport,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 40.0,
                y: 40.0,
                width: 40.0,
                height: 40.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }

    #[test]
    fn clip_to_vbox() {
        let mut affine = cairo::Matrix::identity();
        affine.translate(10.0, 10.0);
        affine.scale(0.40, 0.40);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((0.0, 0.0, 50.0, 50.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            20.0,
            20.0,
            ClipMode::ClipToVbox,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 50.0,
                height: 50.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
extern crate libc;
use core::prelude::*;
use self::libc::{c_void, c_int, size_t};
use self::libc::{mmap, mprotect, munmap};
use self::libc::MAP_FAILED;
use super::page_size;

use core::ptr;

#[cold]
#[inline(never)]
pub fn sys_page_size() -> usize {
  unsafe {
    libc::sysconf(libc::_SC_PAGESIZE) as usize
  }
}

const GUARD_PROT:  c_int = libc::PROT_NONE;
const STACK_PROT:  c_int = libc::PROT_READ
                         | libc::PROT_WRITE;
const STACK_FLAGS: c_int = libc::MAP_STACK
                         | libc::MAP_PRIVATE
                         | libc::MAP_ANON;

pub unsafe fn map_stack(len: usize) -> Option<*mut u8> {
  let ptr = mmap(ptr::null_mut(), len as size_t,
                 STACK_PROT, STACK_FLAGS, -1, 0);
  if ptr != MAP_FAILED {
    Some(ptr as *mut u8)
  }
  else {
    None
  }
}

pub unsafe fn protect_stack(ptr: *mut u8) -> bool {
  mprotect(ptr as *mut c_void, page_size() as size_t, GUARD_PROT) == 0
}

pub unsafe fn unmap_stack(ptr: *mut u8, len: usize) -> bool {
  munmap(ptr as *mut c_void, len as size_t) == 0
}
<commit_msg>add FreeBSD + DragonFlyBSD MAP_STACK workaround<commit_after>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
extern crate libc;
use core::prelude::*;
use self::libc::{c_void, c_int, size_t};
use self::libc::{mmap, mprotect, munmap};
use self::libc::MAP_FAILED;
use super::page_size;

use core::ptr;

#[cold]
#[inline(never)]
pub fn sys_page_size() -> usize {
  unsafe {
    libc::sysconf(libc::_SC_PAGESIZE) as usize
  }
}

const GUARD_PROT:  c_int = libc::PROT_NONE;
const STACK_PROT:  c_int = libc::PROT_READ
                         | libc::PROT_WRITE;
#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly")))]
const STACK_FLAGS: c_int = libc::MAP_STACK
                         | libc::MAP_PRIVATE
                         | libc::MAP_ANON;
// workaround for http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
// according to libgreen, DragonFlyBSD suffers from this too
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
const STACK_FLAGS: c_int = libc::MAP_PRIVATE
                         | libc::MAP_ANON;

pub unsafe fn map_stack(len: usize) -> Option<*mut u8> {
  let ptr = mmap(ptr::null_mut(), len as size_t,
                 STACK_PROT, STACK_FLAGS, -1, 0);
  if ptr != MAP_FAILED {
    Some(ptr as *mut u8)
  }
  else {
    None
  }
}

pub unsafe fn protect_stack(ptr: *mut u8) -> bool {
  mprotect(ptr as *mut c_void, page_size() as size_t, GUARD_PROT) == 0
}

pub unsafe fn unmap_stack(ptr: *mut u8, len: usize) -> bool {
  munmap(ptr as *mut c_void, len as size_t) == 0
}
<|endoftext|>


<commit_before>mod package;
pub mod update;<commit_msg>Update mod.rs<commit_after>mod package;
pub mod update;
pub mod find;<|endoftext|>


<commit_before>/*! Provides packet encoding and decoding functionality, as well as the packet enum.

This module does not handle the checksum.  If it did, it would be incredibly difficult to write Fastnet tests.*/
pub use self::encoder::*;
pub use self::decoder::*;
use uuid;
use std::cmp;

mod encoder;
mod encoder_tests;
mod decoder;
mod decoder_tests;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Packet {
    //Status request and response (channel -1)
    StatusRequest(StatusRequest),
    StatusResponse(StatusResponse),

    //Connection handshake (also channel -1).
    Connect(uuid::Uuid),
    Connected(uuid::Uuid),
    Aborted(String),

    //Heartbeat (channel -2).
    Heartbeat{counter: u64, sent: u64, received: u64},

    Echo{endpoint: uuid::Uuid, uuid: uuid::Uuid},
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatusRequest {
    FastnetQuery,
    VersionQuery,
    ExtensionQuery(String),
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatusResponse {
    FastnetResponse(bool),
    VersionResponse(String),
    ExtensionResponse {name: String, supported: bool},
}

pub const CONNECTION_CHANNEL: i16 = -1;
pub const HEARTBEAT_CHANNEL: i16 = -2;
pub const ECHO_CHANNEL: i16 = -3;

pub const STATUS_REQUEST_SPECIFIER: u8 = 0;
pub const STATUS_RESPONSE_SPECIFIER: u8 = 1;
pub const CONNECT_SPECIFIER: u8 = 2;
pub const CONNECTED_SPECIFIER: u8 = 3;
pub const ABORTED_SPECIFIER: u8 = 4;

//These are used both for query and response.
pub const STATUS_FASTNET_SPECIFIER: u8 = 0;
pub const STATUS_VERSION_SPECIFIER: u8 = 1;
pub const STATUS_EXTENSION_SPECIFIER: u8 = 2;

//Flag bits for data packets, used in the impl of the struct.
pub const DATA_FRAME_START_BIT: u8 = 0;
pub const DATA_FRAME_END_BIT: u8 = 1;
pub const DATA_RELIABLE_BIT: u8 = 2;

/**Represents the part of a data packet that a channel must use to assemble packets.

The actual channel itself is stored in the enum variant.

These are ordered by sequence number, for use in trees.*/
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct DataPacket {
    sequence_number: u64,
    flags: u8,
    payload: Vec<u8>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DataPacketBuilder {
    sequence_number: u64,
    is_reliable: bool,
    is_start: bool,
    is_end: bool,
    payload: Vec<u8>,
}

impl DataPacketBuilder {
    /**Initial state is unreliable, mid-frame, and empty payload.*/
    pub fn new(sequence_number: u64)->DataPacketBuilder {
        DataPacketBuilder::with_payload(sequence_number, Vec::default())
    }

    /**Configures the builder for mid-frame, unreliable but using the specified payload.*/
    pub fn with_payload(sequence_number: u64, payload: Vec<u8>)->DataPacketBuilder {
        DataPacketBuilder {
            sequence_number: sequence_number,
            is_reliable: false,
            is_start: false,
            is_end: false,
            payload: payload,
        }
    }

    pub fn set_payload(&mut self, payload: Vec<u8>) {
        self.payload = payload;
    }

    pub fn set_reliable(&mut self, reliable: bool) {
        self.is_reliable = reliable;
    }

    pub fn set_start(&mut self, start: bool) {
        self.is_start = start;
    }

    pub fn set_end(&mut self, end: bool) {
        self.is_end = end;
    }

    pub fn set_sequence_number(&mut self, sequence_number: u64) {
        self.sequence_number = sequence_number;
    }

    pub fn build(self)->Option<DataPacket> {
        let start_flag  = (self.is_start as u8) << DATA_FRAME_START_BIT;
        let end_flag = (self.is_end as u8) << DATA_FRAME_END_BIT;
        let reliable_flag = (self.is_reliable as u8) << DATA_RELIABLE_BIT;
        let flags = start_flag | end_flag | reliable_flag;
        Some(DataPacket {
            sequence_number: self.sequence_number,
            flags: flags,
            payload: self.payload,
        })
    }
}

impl DataPacket {
    pub fn is_reliable(&self)->bool {
        (self.flags & DATA_RELIABLE_BIT) > 0
    }

    pub fn is_frame_start(&self)->bool {
        (self.flags & DATA_FRAME_START_BIT) > 0
    }

    pub fn is_frame_end(&self)->bool {
        (self.flags & DATA_FRAME_END_BIT) > 0
    }

    pub fn borrow_payload(&self)->&Vec<u8> {
        &self.payload
    }

    pub fn into_payload(self)->Vec<u8> {
        self.payload
    }
}<commit_msg>Ability to get sequence numbers out of DataPacket.<commit_after>/*! Provides packet encoding and decoding functionality, as well as the packet enum.

This module does not handle the checksum.  If it did, it would be incredibly difficult to write Fastnet tests.*/
pub use self::encoder::*;
pub use self::decoder::*;
use uuid;
use std::cmp;

mod encoder;
mod encoder_tests;
mod decoder;
mod decoder_tests;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Packet {
    //Status request and response (channel -1)
    StatusRequest(StatusRequest),
    StatusResponse(StatusResponse),

    //Connection handshake (also channel -1).
    Connect(uuid::Uuid),
    Connected(uuid::Uuid),
    Aborted(String),

    //Heartbeat (channel -2).
    Heartbeat{counter: u64, sent: u64, received: u64},

    Echo{endpoint: uuid::Uuid, uuid: uuid::Uuid},
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatusRequest {
    FastnetQuery,
    VersionQuery,
    ExtensionQuery(String),
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatusResponse {
    FastnetResponse(bool),
    VersionResponse(String),
    ExtensionResponse {name: String, supported: bool},
}

pub const CONNECTION_CHANNEL: i16 = -1;
pub const HEARTBEAT_CHANNEL: i16 = -2;
pub const ECHO_CHANNEL: i16 = -3;

pub const STATUS_REQUEST_SPECIFIER: u8 = 0;
pub const STATUS_RESPONSE_SPECIFIER: u8 = 1;
pub const CONNECT_SPECIFIER: u8 = 2;
pub const CONNECTED_SPECIFIER: u8 = 3;
pub const ABORTED_SPECIFIER: u8 = 4;

//These are used both for query and response.
pub const STATUS_FASTNET_SPECIFIER: u8 = 0;
pub const STATUS_VERSION_SPECIFIER: u8 = 1;
pub const STATUS_EXTENSION_SPECIFIER: u8 = 2;

//Flag bits for data packets, used in the impl of the struct.
pub const DATA_FRAME_START_BIT: u8 = 0;
pub const DATA_FRAME_END_BIT: u8 = 1;
pub const DATA_RELIABLE_BIT: u8 = 2;

/**Represents the part of a data packet that a channel must use to assemble packets.

The actual channel itself is stored in the enum variant.

These are ordered by sequence number, for use in trees.*/
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct DataPacket {
    sequence_number: u64,
    flags: u8,
    payload: Vec<u8>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DataPacketBuilder {
    sequence_number: u64,
    is_reliable: bool,
    is_start: bool,
    is_end: bool,
    payload: Vec<u8>,
}

impl DataPacketBuilder {
    /**Initial state is unreliable, mid-frame, and empty payload.*/
    pub fn new(sequence_number: u64)->DataPacketBuilder {
        DataPacketBuilder::with_payload(sequence_number, Vec::default())
    }

    /**Configures the builder for mid-frame, unreliable but using the specified payload.*/
    pub fn with_payload(sequence_number: u64, payload: Vec<u8>)->DataPacketBuilder {
        DataPacketBuilder {
            sequence_number: sequence_number,
            is_reliable: false,
            is_start: false,
            is_end: false,
            payload: payload,
        }
    }

    pub fn set_payload(&mut self, payload: Vec<u8>) {
        self.payload = payload;
    }

    pub fn set_reliable(&mut self, reliable: bool) {
        self.is_reliable = reliable;
    }

    pub fn set_start(&mut self, start: bool) {
        self.is_start = start;
    }

    pub fn set_end(&mut self, end: bool) {
        self.is_end = end;
    }

    pub fn set_sequence_number(&mut self, sequence_number: u64) {
        self.sequence_number = sequence_number;
    }

    pub fn build(self)->Option<DataPacket> {
        let start_flag  = (self.is_start as u8) << DATA_FRAME_START_BIT;
        let end_flag = (self.is_end as u8) << DATA_FRAME_END_BIT;
        let reliable_flag = (self.is_reliable as u8) << DATA_RELIABLE_BIT;
        let flags = start_flag | end_flag | reliable_flag;
        Some(DataPacket {
            sequence_number: self.sequence_number,
            flags: flags,
            payload: self.payload,
        })
    }
}

impl DataPacket {
    pub fn is_reliable(&self)->bool {
        (self.flags & DATA_RELIABLE_BIT) > 0
    }

    pub fn is_frame_start(&self)->bool {
        (self.flags & DATA_FRAME_START_BIT) > 0
    }

    pub fn is_frame_end(&self)->bool {
        (self.flags & DATA_FRAME_END_BIT) > 0
    }

    pub fn sequence_number(&self)->u64 {
        self.sequence_number
    }

    pub fn borrow_payload(&self)->&Vec<u8> {
        &self.payload
    }

    pub fn into_payload(self)->Vec<u8> {
        self.payload
    }
}<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{
    hash::{Hash, Hasher},
    sync::Arc,
};

use mbe::MacroRules;
use ra_db::{salsa, FileId};
use ra_prof::profile;
use ra_syntax::{ast, AstNode, Parse, SyntaxNode};

use crate::{
    db::{AstDatabase, DefDatabase, InternDatabase},
    AstId, Crate, FileAstId, Module, Source,
};

/// hir makes heavy use of ids: integer (u32) handlers to various things. You
/// can think of id as a pointer (but without a lifetime) or a file descriptor
/// (but for hir objects).
///
/// This module defines a bunch of ids we are using. The most important ones are
/// probably `HirFileId` and `DefId`.

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &impl InternDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(macro_file) => {
                let loc = macro_file.macro_call_id.loc(db);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Get the crate which the macro lives in, if it is a macro file.
    pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
        match self.0 {
            HirFileIdRepr::File(_) => None,
            HirFileIdRepr::Macro(macro_file) => {
                let loc = macro_file.macro_call_id.loc(db);
                Some(loc.def.krate)
            }
        }
    }

    pub(crate) fn parse_or_expand_query(
        db: &impl AstDatabase,
        file_id: HirFileId,
    ) -> Option<SyntaxNode> {
        match file_id.0 {
            HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
            HirFileIdRepr::Macro(macro_file) => {
                db.parse_macro(macro_file).map(|it| it.syntax_node())
            }
        }
    }

    pub(crate) fn parse_macro_query(
        db: &impl AstDatabase,
        macro_file: MacroFile,
    ) -> Option<Parse<SyntaxNode>> {
        let _p = profile("parse_macro_query");
        let macro_call_id = macro_file.macro_call_id;
        let tt = db
            .macro_expand(macro_call_id)
            .map_err(|err| {
                // Note:
                // The final goal we would like to make all parse_macro success,
                // such that the following log will not call anyway.
                log::warn!("fail on macro_parse: (reason: {})", err,);
            })
            .ok()?;
        match macro_file.macro_file_kind {
            MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
            MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    File(FileId),
    Macro(MacroFile),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum MacroFileKind {
    Items,
    Expr,
}

impl From<FileId> for HirFileId {
    fn from(file_id: FileId) -> HirFileId {
        HirFileId(HirFileIdRepr::File(file_id))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub(crate) ast_id: AstId<ast::MacroCall>,
    pub(crate) krate: Crate,
}

pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
    let macro_call = id.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some(Arc::new(rules))
}

pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
    let loc = id.loc(db);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(&arg)?;
    Some(Arc::new(tt))
}

pub(crate) fn macro_expand_query(
    db: &impl AstDatabase,
    id: MacroCallId,
) -> Result<Arc<tt::Subtree>, String> {
    let loc = id.loc(db);
    let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }
    Ok(Arc::new(tt))
}

macro_rules! impl_intern_key {
    ($name:ident) => {
        impl salsa::InternKey for $name {
            fn from_intern_id(v: salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> salsa::InternId {
                self.0
            }
        }
    };
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl_intern_key!(MacroCallId);

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub(crate) def: MacroDefId,
    pub(crate) ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc {
        db.lookup_intern_macro(self)
    }

    pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        HirFileId(HirFileIdRepr::Macro(macro_file))
    }
}

impl MacroCallLoc {
    pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId {
        db.intern_macro(self)
    }
}

#[derive(Debug)]
pub struct ItemLoc<N: AstNode> {
    pub(crate) module: Module,
    ast_id: AstId<N>,
}

impl<N: AstNode> PartialEq for ItemLoc<N> {
    fn eq(&self, other: &Self) -> bool {
        self.module == other.module && self.ast_id == other.ast_id
    }
}
impl<N: AstNode> Eq for ItemLoc<N> {}
impl<N: AstNode> Hash for ItemLoc<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.module.hash(hasher);
        self.ast_id.hash(hasher);
    }
}

impl<N: AstNode> Clone for ItemLoc<N> {
    fn clone(&self) -> ItemLoc<N> {
        ItemLoc { module: self.module, ast_id: self.ast_id }
    }
}

#[derive(Clone, Copy)]
pub(crate) struct LocationCtx<DB> {
    db: DB,
    module: Module,
    file_id: HirFileId,
}

impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
    pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
        LocationCtx { db, module, file_id }
    }
}

impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> {
    pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
    where
        N: AstNode,
        DEF: AstItemDef<N>,
    {
        DEF::from_ast(self, ast)
    }
}

pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self;
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>;

    fn from_ast(ctx: LocationCtx<&(impl AstDatabase + DefDatabase)>, ast: &N) -> Self {
        let items = ctx.db.ast_id_map(ctx.file_id);
        let item_id = items.ast_id(ast);
        Self::from_ast_id(ctx, item_id)
    }
    fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
        let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
        Self::intern(ctx.db, loc)
    }
    fn source(self, db: &(impl AstDatabase + DefDatabase)) -> Source<N> {
        let loc = self.lookup_intern(db);
        let ast = loc.ast_id.to_node(db);
        Source { file_id: loc.ast_id.file_id(), ast }
    }
    fn module(self, db: &impl DefDatabase) -> Module {
        let loc = self.lookup_intern(db);
        loc.module
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(salsa::InternId);
impl_intern_key!(FunctionId);

impl AstItemDef<ast::FnDef> for FunctionId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
        db.intern_function(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> {
        db.lookup_intern_function(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructId(salsa::InternId);
impl_intern_key!(StructId);
impl AstItemDef<ast::StructDef> for StructId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
        db.intern_struct(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> {
        db.lookup_intern_struct(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumId(salsa::InternId);
impl_intern_key!(EnumId);
impl AstItemDef<ast::EnumDef> for EnumId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
        db.intern_enum(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> {
        db.lookup_intern_enum(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstId(salsa::InternId);
impl_intern_key!(ConstId);
impl AstItemDef<ast::ConstDef> for ConstId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
        db.intern_const(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> {
        db.lookup_intern_const(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticId(salsa::InternId);
impl_intern_key!(StaticId);
impl AstItemDef<ast::StaticDef> for StaticId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
        db.intern_static(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> {
        db.lookup_intern_static(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TraitId(salsa::InternId);
impl_intern_key!(TraitId);
impl AstItemDef<ast::TraitDef> for TraitId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
        db.intern_trait(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> {
        db.lookup_intern_trait(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeAliasId(salsa::InternId);
impl_intern_key!(TypeAliasId);
impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
    fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
        db.intern_type_alias(loc)
    }
    fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> {
        db.lookup_intern_type_alias(self)
    }
}

/// This exists just for Chalk, because Chalk just has a single `StructId` where
/// we have different kinds of ADTs, primitive types and special type
/// constructors like tuples and function pointers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeCtorId(salsa::InternId);
impl_intern_key!(TypeCtorId);

/// This exists just for Chalk, because our ImplIds are only unique per module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GlobalImplId(salsa::InternId);
impl_intern_key!(GlobalImplId);
<commit_msg>weaken requirements of AstDef<commit_after>//! FIXME: write short doc here

use std::{
    hash::{Hash, Hasher},
    sync::Arc,
};

use mbe::MacroRules;
use ra_db::{salsa, FileId};
use ra_prof::profile;
use ra_syntax::{ast, AstNode, Parse, SyntaxNode};

use crate::{
    db::{AstDatabase, InternDatabase},
    AstId, Crate, FileAstId, Module, Source,
};

/// hir makes heavy use of ids: integer (u32) handlers to various things. You
/// can think of id as a pointer (but without a lifetime) or a file descriptor
/// (but for hir objects).
///
/// This module defines a bunch of ids we are using. The most important ones are
/// probably `HirFileId` and `DefId`.

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &impl InternDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::File(file_id) => file_id,
            HirFileIdRepr::Macro(macro_file) => {
                let loc = macro_file.macro_call_id.loc(db);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Get the crate which the macro lives in, if it is a macro file.
    pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
        match self.0 {
            HirFileIdRepr::File(_) => None,
            HirFileIdRepr::Macro(macro_file) => {
                let loc = macro_file.macro_call_id.loc(db);
                Some(loc.def.krate)
            }
        }
    }

    pub(crate) fn parse_or_expand_query(
        db: &impl AstDatabase,
        file_id: HirFileId,
    ) -> Option<SyntaxNode> {
        match file_id.0 {
            HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
            HirFileIdRepr::Macro(macro_file) => {
                db.parse_macro(macro_file).map(|it| it.syntax_node())
            }
        }
    }

    pub(crate) fn parse_macro_query(
        db: &impl AstDatabase,
        macro_file: MacroFile,
    ) -> Option<Parse<SyntaxNode>> {
        let _p = profile("parse_macro_query");
        let macro_call_id = macro_file.macro_call_id;
        let tt = db
            .macro_expand(macro_call_id)
            .map_err(|err| {
                // Note:
                // The final goal we would like to make all parse_macro success,
                // such that the following log will not call anyway.
                log::warn!("fail on macro_parse: (reason: {})", err,);
            })
            .ok()?;
        match macro_file.macro_file_kind {
            MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
            MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    File(FileId),
    Macro(MacroFile),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum MacroFileKind {
    Items,
    Expr,
}

impl From<FileId> for HirFileId {
    fn from(file_id: FileId) -> HirFileId {
        HirFileId(HirFileIdRepr::File(file_id))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub(crate) ast_id: AstId<ast::MacroCall>,
    pub(crate) krate: Crate,
}

pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
    let macro_call = id.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some(Arc::new(rules))
}

pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
    let loc = id.loc(db);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, _) = mbe::ast_to_token_tree(&arg)?;
    Some(Arc::new(tt))
}

pub(crate) fn macro_expand_query(
    db: &impl AstDatabase,
    id: MacroCallId,
) -> Result<Arc<tt::Subtree>, String> {
    let loc = id.loc(db);
    let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }
    Ok(Arc::new(tt))
}

macro_rules! impl_intern_key {
    ($name:ident) => {
        impl salsa::InternKey for $name {
            fn from_intern_id(v: salsa::InternId) -> Self {
                $name(v)
            }
            fn as_intern_id(&self) -> salsa::InternId {
                self.0
            }
        }
    };
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl_intern_key!(MacroCallId);

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub(crate) def: MacroDefId,
    pub(crate) ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc {
        db.lookup_intern_macro(self)
    }

    pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        HirFileId(HirFileIdRepr::Macro(macro_file))
    }
}

impl MacroCallLoc {
    pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId {
        db.intern_macro(self)
    }
}

#[derive(Debug)]
pub struct ItemLoc<N: AstNode> {
    pub(crate) module: Module,
    ast_id: AstId<N>,
}

impl<N: AstNode> PartialEq for ItemLoc<N> {
    fn eq(&self, other: &Self) -> bool {
        self.module == other.module && self.ast_id == other.ast_id
    }
}
impl<N: AstNode> Eq for ItemLoc<N> {}
impl<N: AstNode> Hash for ItemLoc<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.module.hash(hasher);
        self.ast_id.hash(hasher);
    }
}

impl<N: AstNode> Clone for ItemLoc<N> {
    fn clone(&self) -> ItemLoc<N> {
        ItemLoc { module: self.module, ast_id: self.ast_id }
    }
}

#[derive(Clone, Copy)]
pub(crate) struct LocationCtx<DB> {
    db: DB,
    module: Module,
    file_id: HirFileId,
}

impl<'a, DB> LocationCtx<&'a DB> {
    pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
        LocationCtx { db, module, file_id }
    }
}

impl<'a, DB: AstDatabase> LocationCtx<&'a DB> {
    pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
    where
        N: AstNode,
        DEF: AstItemDef<N>,
    {
        DEF::from_ast(self, ast)
    }
}

pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;

    fn from_ast(ctx: LocationCtx<&impl AstDatabase>, ast: &N) -> Self {
        let items = ctx.db.ast_id_map(ctx.file_id);
        let item_id = items.ast_id(ast);
        Self::from_ast_id(ctx, item_id)
    }
    fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
        let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
        Self::intern(ctx.db, loc)
    }
    fn source(self, db: &impl AstDatabase) -> Source<N> {
        let loc = self.lookup_intern(db);
        let ast = loc.ast_id.to_node(db);
        Source { file_id: loc.ast_id.file_id(), ast }
    }
    fn module(self, db: &impl InternDatabase) -> Module {
        let loc = self.lookup_intern(db);
        loc.module
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(salsa::InternId);
impl_intern_key!(FunctionId);

impl AstItemDef<ast::FnDef> for FunctionId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
        db.intern_function(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
        db.lookup_intern_function(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructId(salsa::InternId);
impl_intern_key!(StructId);
impl AstItemDef<ast::StructDef> for StructId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
        db.intern_struct(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
        db.lookup_intern_struct(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumId(salsa::InternId);
impl_intern_key!(EnumId);
impl AstItemDef<ast::EnumDef> for EnumId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
        db.intern_enum(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
        db.lookup_intern_enum(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstId(salsa::InternId);
impl_intern_key!(ConstId);
impl AstItemDef<ast::ConstDef> for ConstId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
        db.intern_const(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
        db.lookup_intern_const(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticId(salsa::InternId);
impl_intern_key!(StaticId);
impl AstItemDef<ast::StaticDef> for StaticId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
        db.intern_static(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
        db.lookup_intern_static(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TraitId(salsa::InternId);
impl_intern_key!(TraitId);
impl AstItemDef<ast::TraitDef> for TraitId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
        db.intern_trait(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
        db.lookup_intern_trait(self)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeAliasId(salsa::InternId);
impl_intern_key!(TypeAliasId);
impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
        db.intern_type_alias(loc)
    }
    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
        db.lookup_intern_type_alias(self)
    }
}

/// This exists just for Chalk, because Chalk just has a single `StructId` where
/// we have different kinds of ADTs, primitive types and special type
/// constructors like tuples and function pointers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeCtorId(salsa::InternId);
impl_intern_key!(TypeCtorId);

/// This exists just for Chalk, because our ImplIds are only unique per module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GlobalImplId(salsa::InternId);
impl_intern_key!(GlobalImplId);
<|endoftext|>


<commit_before>use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use bencode;

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum RoutePacket {
    FindNode { target_address: String, transaction_id: String },
    Nodes { nodes: String, transaction_id: String },
}

impl RoutePacket {
    pub fn new_from_slice(v: &[u8]) -> Result<RoutePacket, <bencode::Decoder as Decoder>::Error> {
        let mut bencode = bencode::from_buffer(v).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        RoutePacket::decode(&mut decoder)
    }
}

impl Decodable for RoutePacket {
    fn decode<D: Decoder>(d: &mut D) -> Result<RoutePacket, D::Error> {
        d.read_struct("RoutePacket", 3, |d| {
            let query_res = d.read_struct_field("q", 0, D::read_str);
            match query_res {
                Ok(query) => {
                    match query.as_ref() {
                        "fn" => {
                            let target_address = try!(d.read_struct_field("tar", 0, D::read_str));
                            let transaction_id = try!(d.read_struct_field("txid", 1, D::read_str));
                            Ok(RoutePacket::FindNode { target_address: target_address, transaction_id: transaction_id })
                        },
                        _ => Err(d.error(&format!("Unknown query type: {}", query))),
                    }
                },
                Err(_) => { // 'q' is not given (or not readable, TODO: fix this)
                    let nodes = try!(d.read_struct_field("n", 0, D::read_str));
                    let transaction_id = try!(d.read_struct_field("txid", 1, D::read_str));
                    Ok(RoutePacket::Nodes { nodes: nodes, transaction_id: transaction_id })
                },
            }
        })
    }
}

impl Encodable for RoutePacket {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("RoutePacket", 3, |s| {
            match *self {
                RoutePacket::FindNode { ref target_address, ref transaction_id } => {
                    try!(s.emit_struct_field("q", 0, |s| {
                        s.emit_str("fn")
                    }));
                    try!(s.emit_struct_field("tar", 1, |s| {
                        s.emit_str(target_address)
                    }));
                    try!(s.emit_struct_field("txid", 2, |s| {
                        s.emit_str(transaction_id)
                    }));
                    Ok(())
                },
                RoutePacket::Nodes { ref nodes, ref transaction_id } => {
                    try!(s.emit_struct_field("n", 0, |s| {
                        s.emit_str(nodes)
                    }));
                    try!(s.emit_struct_field("txid", 1, |s| {
                        s.emit_str(transaction_id)
                    }));
                    Ok(())
                },
            }
        })
    }
}

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

    #[test]
    fn test_fn() {
        let s = "d1:q2:fn3:tar16:abcdefghhijklmno4:txid5:12345e".as_bytes();
        let m = RoutePacket::FindNode {
            target_address: "abcdefghhijklmno".to_owned(),
            transaction_id: "12345".to_owned()
        };

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        let s_decoded = RoutePacket::decode(&mut decoder);

        let m_encoded = bencode::encode(&m);

        assert_eq!(s_decoded, Ok(m));
        assert_eq!(m_encoded.unwrap(), s);
    }

    #[test]
    fn test_n() {
        let s = "d1:n80:cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde23456784:txid5:12345e".as_bytes();
        let m = RoutePacket::Nodes {
            nodes: "cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde2345678".to_owned(),
            transaction_id: "12345".to_owned()
        };

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        let s_decoded = RoutePacket::decode(&mut decoder);

        let m_encoded = bencode::encode(&m);

        assert_eq!(s_decoded, Ok(m));
        assert_eq!(m_encoded.unwrap(), s);
    }

    #[test]
    fn test_gp() {
        let s = b"d002:eii0e2:es5:a\x14E\x81\x001:pi17e1:q2:gp3:tar8:\x00\x00\x00\x00\x00\x00\x00\x004:txid12:\x0b\xf2\x17\xf4\x92\xa4\xc4d\xc6\x03[\xdde";

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        RoutePacket::decode(&mut decoder).unwrap();
    }
}
<commit_msg>Add support for gp router queries.<commit_after>use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use bencode;

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum RoutePacket {
    GetPeers { transaction_id: String },
    FindNode { target_address: String, transaction_id: String },
    Nodes { nodes: String, transaction_id: String },
}

impl RoutePacket {
    pub fn new_from_slice(v: &[u8]) -> Result<RoutePacket, <bencode::Decoder as Decoder>::Error> {
        let mut bencode = bencode::from_buffer(v).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        RoutePacket::decode(&mut decoder)
    }
}

impl Decodable for RoutePacket {
    fn decode<D: Decoder>(d: &mut D) -> Result<RoutePacket, D::Error> {
        d.read_struct("RoutePacket", 3, |d| {
            let query_res = d.read_struct_field("q", 0, D::read_str);
            match query_res {
                Ok(query) => {
                    match query.as_ref() {
                        "gp" => {
                            let transaction_id = try!(d.read_struct_field("txid", 1, D::read_str));
                            Ok(RoutePacket::GetPeers { transaction_id: transaction_id })
                        },
                        "fn" => {
                            let target_address = try!(d.read_struct_field("tar", 0, D::read_str));
                            let transaction_id = try!(d.read_struct_field("txid", 1, D::read_str));
                            Ok(RoutePacket::FindNode { target_address: target_address, transaction_id: transaction_id })
                        },
                        _ => Err(d.error(&format!("Unknown query type: {}", query))),
                    }
                },
                Err(_) => { // 'q' is not given (or not readable, TODO: fix this)
                    let nodes = try!(d.read_struct_field("n", 0, D::read_str));
                    let transaction_id = try!(d.read_struct_field("txid", 1, D::read_str));
                    Ok(RoutePacket::Nodes { nodes: nodes, transaction_id: transaction_id })
                },
            }
        })
    }
}

impl Encodable for RoutePacket {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("RoutePacket", 3, |s| {
            match *self {
                RoutePacket::FindNode { ref target_address, ref transaction_id } => {
                    try!(s.emit_struct_field("q", 0, |s| {
                        s.emit_str("fn")
                    }));
                    try!(s.emit_struct_field("tar", 1, |s| {
                        s.emit_str(target_address)
                    }));
                    try!(s.emit_struct_field("txid", 2, |s| {
                        s.emit_str(transaction_id)
                    }));
                    Ok(())
                },
                RoutePacket::Nodes { ref nodes, ref transaction_id } => {
                    try!(s.emit_struct_field("n", 0, |s| {
                        s.emit_str(nodes)
                    }));
                    try!(s.emit_struct_field("txid", 1, |s| {
                        s.emit_str(transaction_id)
                    }));
                    Ok(())
                },
            }
        })
    }
}

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

    #[test]
    fn test_fn() {
        let s = "d1:q2:fn3:tar16:abcdefghhijklmno4:txid5:12345e".as_bytes();
        let m = RoutePacket::FindNode {
            target_address: "abcdefghhijklmno".to_owned(),
            transaction_id: "12345".to_owned()
        };

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        let s_decoded = RoutePacket::decode(&mut decoder);

        let m_encoded = bencode::encode(&m);

        assert_eq!(s_decoded, Ok(m));
        assert_eq!(m_encoded.unwrap(), s);
    }

    #[test]
    fn test_n() {
        let s = "d1:n80:cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde23456784:txid5:12345e".as_bytes();
        let m = RoutePacket::Nodes {
            nodes: "cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde2345678".to_owned(),
            transaction_id: "12345".to_owned()
        };

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        let s_decoded = RoutePacket::decode(&mut decoder);

        let m_encoded = bencode::encode(&m);

        assert_eq!(s_decoded, Ok(m));
        assert_eq!(m_encoded.unwrap(), s);
    }

    #[test]
    fn test_gp() {
        let s = b"d002:eii0e2:es5:a\x14E\x81\x001:pi17e1:q2:gp3:tar8:\x00\x00\x00\x00\x00\x00\x00\x004:txid12:\x0b\xf2\x17\xf4\x92\xa4\xc4d\xc6\x03[\xdde";

        let mut bencode = bencode::from_buffer(s).unwrap();
        let mut decoder = bencode::Decoder::new(&mut bencode);
        RoutePacket::decode(&mut decoder).unwrap();
    }
}
<|endoftext|>


<commit_before>use crate::common::BinarySerializable;
use std::io;
use std::io::Read;
use std::io::Write;

/// `Field` is represented by an unsigned 32-bit integer type
/// The schema holds the mapping between field names and `Field` objects.
#[derive(
    Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct Field(u32);

impl Field {
    /// Create a new field object for the given FieldId.
    pub fn from_field_id(field_id: u32) -> Field {
        Field(field_id)
    }

    /// Returns a u32 identifying uniquely a field within a schema.
    #[allow(clippy::trivially_copy_pass_by_ref)]
    pub fn field_id(&self) -> u32 {
        self.0
    }
}

impl BinarySerializable for Field {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.0.serialize(writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Field> {
        u32::deserialize(reader).map(Field)
    }
}
<commit_msg>Made field methods const fns (#823)<commit_after>use crate::common::BinarySerializable;
use std::io;
use std::io::Read;
use std::io::Write;

/// `Field` is represented by an unsigned 32-bit integer type
/// The schema holds the mapping between field names and `Field` objects.
#[derive(
    Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct Field(u32);

impl Field {
    /// Create a new field object for the given FieldId.
    pub const fn from_field_id(field_id: u32) -> Field {
        Field(field_id)
    }

    /// Returns a u32 identifying uniquely a field within a schema.
    #[allow(clippy::trivially_copy_pass_by_ref)]
    pub const fn field_id(&self) -> u32 {
        self.0
    }
}

impl BinarySerializable for Field {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.0.serialize(writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Field> {
        u32::deserialize(reader).map(Field)
    }
}
<|endoftext|>


<commit_before>use crate::sys;
use crate::sys::SDL_bool;

pub const CACHELINESIZE: u8 = 128;

pub fn cpu_count() -> i32 {
    unsafe { sys::SDL_GetCPUCount() }
}

pub fn cpu_cache_line_size() -> i32 {
    unsafe { sys::SDL_GetCPUCacheLineSize() }
}

pub fn has_rdtsc() -> bool {
    unsafe { sys::SDL_HasRDTSC() == SDL_bool::SDL_TRUE }
}

pub fn has_alti_vec() -> bool {
    unsafe { sys::SDL_HasAltiVec() == SDL_bool::SDL_TRUE }
}

pub fn has_mmx() -> bool {
    unsafe { sys::SDL_HasMMX() == SDL_bool::SDL_TRUE }
}

pub fn has_3d_now() -> bool {
    unsafe { sys::SDL_Has3DNow() == SDL_bool::SDL_TRUE }
}

pub fn has_sse() -> bool {
    unsafe { sys::SDL_HasSSE() == SDL_bool::SDL_TRUE }
}

pub fn has_sse2() -> bool {
    unsafe { sys::SDL_HasSSE2() == SDL_bool::SDL_TRUE }
}

pub fn has_sse3() -> bool {
    unsafe { sys::SDL_HasSSE3() == SDL_bool::SDL_TRUE }
}

pub fn has_sse41() -> bool {
    unsafe { sys::SDL_HasSSE41() == SDL_bool::SDL_TRUE }
}

pub fn has_sse42() -> bool {
    unsafe { sys::SDL_HasSSE42() == SDL_bool::SDL_TRUE }
}

pub fn has_avx() -> bool {
    unsafe { sys::SDL_HasAVX() == SDL_bool::SDL_TRUE }
}

pub fn system_ram() -> i32 {
    unsafe { sys::SDL_GetSystemRAM() }
}
<commit_msg>Add has_avx2/has_avx512f<commit_after>use crate::sys;
use crate::sys::SDL_bool;

pub const CACHELINESIZE: u8 = 128;

pub fn cpu_count() -> i32 {
    unsafe { sys::SDL_GetCPUCount() }
}

pub fn cpu_cache_line_size() -> i32 {
    unsafe { sys::SDL_GetCPUCacheLineSize() }
}

pub fn has_rdtsc() -> bool {
    unsafe { sys::SDL_HasRDTSC() == SDL_bool::SDL_TRUE }
}

pub fn has_alti_vec() -> bool {
    unsafe { sys::SDL_HasAltiVec() == SDL_bool::SDL_TRUE }
}

pub fn has_mmx() -> bool {
    unsafe { sys::SDL_HasMMX() == SDL_bool::SDL_TRUE }
}

pub fn has_3d_now() -> bool {
    unsafe { sys::SDL_Has3DNow() == SDL_bool::SDL_TRUE }
}

pub fn has_sse() -> bool {
    unsafe { sys::SDL_HasSSE() == SDL_bool::SDL_TRUE }
}

pub fn has_sse2() -> bool {
    unsafe { sys::SDL_HasSSE2() == SDL_bool::SDL_TRUE }
}

pub fn has_sse3() -> bool {
    unsafe { sys::SDL_HasSSE3() == SDL_bool::SDL_TRUE }
}

pub fn has_sse41() -> bool {
    unsafe { sys::SDL_HasSSE41() == SDL_bool::SDL_TRUE }
}

pub fn has_sse42() -> bool {
    unsafe { sys::SDL_HasSSE42() == SDL_bool::SDL_TRUE }
}

pub fn has_avx() -> bool {
    unsafe { sys::SDL_HasAVX() == SDL_bool::SDL_TRUE }
}

pub fn has_avx2() -> bool {
    unsafe { sys::SDL_HasAVX2() == SDL_bool::SDL_TRUE }
}

pub fn has_avx512f() -> bool {
    unsafe { sys::SDL_HasAVX512F() == SDL_bool::SDL_TRUE }
}

pub fn system_ram() -> i32 {
    unsafe { sys::SDL_GetSystemRAM() }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Fabian Schuiki

use crate::{
    crate_prelude::*,
    hir::HirNode,
    ty::{bit_size_of_type, Type, TypeKind},
    value::ValueKind,
    ParamEnv, ParamEnvBinding,
};
use num::traits::{cast::ToPrimitive, sign::Signed};

/// Determine the type of a node.
pub(crate) fn type_of<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Port(p) => cx.map_to_type(p.ty, env),
        HirNode::Expr(e) => match e.kind {
            hir::ExprKind::IntConst(width, _) => Ok(cx.mkty_int(width)),
            hir::ExprKind::UnsizedConst(_) => Ok(cx.mkty_int(1)),
            hir::ExprKind::TimeConst(_) => Ok(cx.mkty_time()),
            hir::ExprKind::Ident(_) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::Unary(op, arg) => {
                let arg_ty = cx.type_of(arg, env)?;
                Ok(match op {
                    hir::UnaryOp::Neg
                    | hir::UnaryOp::BitNot
                    | hir::UnaryOp::PreInc
                    | hir::UnaryOp::PreDec
                    | hir::UnaryOp::PostInc
                    | hir::UnaryOp::PostDec => arg_ty,
                    hir::UnaryOp::LogicNot => cx.mkty_bit(),
                    _ => {
                        error!("{:#?}", hir);
                        return cx.unimp_msg("type analysis of", &hir);
                    }
                })
            }
            hir::ExprKind::Binary(op, lhs, rhs) => {
                let lhs_ty = cx.type_of(lhs, env)?;
                let _rhs_ty = cx.type_of(rhs, env)?;
                Ok(match op {
                    hir::BinaryOp::Add
                    | hir::BinaryOp::Sub
                    | hir::BinaryOp::Mul
                    | hir::BinaryOp::Div
                    | hir::BinaryOp::Mod
                    | hir::BinaryOp::Pow
                    | hir::BinaryOp::LogicShL
                    | hir::BinaryOp::LogicShR
                    | hir::BinaryOp::ArithShL
                    | hir::BinaryOp::ArithShR
                    | hir::BinaryOp::BitAnd
                    | hir::BinaryOp::BitNand
                    | hir::BinaryOp::BitOr
                    | hir::BinaryOp::BitNor
                    | hir::BinaryOp::BitXor
                    | hir::BinaryOp::BitXnor => lhs_ty,
                    hir::BinaryOp::Eq
                    | hir::BinaryOp::Neq
                    | hir::BinaryOp::Lt
                    | hir::BinaryOp::Leq
                    | hir::BinaryOp::Gt
                    | hir::BinaryOp::Geq
                    | hir::BinaryOp::LogicAnd
                    | hir::BinaryOp::LogicOr => cx.mkty_bit(),
                    _ => {
                        error!("{:#?}", hir);
                        return cx.unimp_msg("type analysis of", &hir);
                    }
                })
            }
            hir::ExprKind::Field(..) => {
                let (_, _, field_id) = cx.resolve_field_access(node_id, env)?;
                cx.type_of(field_id, env)
            }
            hir::ExprKind::Index(target, mode) => {
                let target_ty = cx.type_of(target, env)?;
                match mode {
                    hir::IndexMode::One(..) => match *target_ty {
                        TypeKind::PackedArray(_, ty) => Ok(ty),
                        TypeKind::Int(_, ty::Domain::TwoValued) => Ok(cx.mkty_bit()),
                        TypeKind::Int(_, ty::Domain::FourValued) => Ok(cx.mkty_logic()),
                        _ => {
                            let hir = cx.hir_of(target)?;
                            cx.emit(
                                DiagBuilder2::error(format!(
                                    "{} cannot be indexed into",
                                    hir.desc_full()
                                ))
                                .span(hir.human_span()),
                            );
                            Err(())
                        }
                    },
                    hir::IndexMode::Many(..) => Ok(target_ty),
                }
            }
            hir::ExprKind::Builtin(hir::BuiltinCall::Clog2(_))
            | hir::ExprKind::Builtin(hir::BuiltinCall::Bits(_)) => Ok(cx.mkty_int(32)),
            hir::ExprKind::Builtin(hir::BuiltinCall::Signed(arg))
            | hir::ExprKind::Builtin(hir::BuiltinCall::Unsigned(arg)) => cx.type_of(arg, env),
            hir::ExprKind::Ternary(_cond, true_expr, _false_expr) => cx.type_of(true_expr, env),
            hir::ExprKind::Scope(..) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::PositionalPattern(..)
            | hir::ExprKind::NamedPattern(..)
            | hir::ExprKind::RepeatPattern(..)
            | hir::ExprKind::EmptyPattern => cx.type_of(cx.parent_node_id(node_id).unwrap(), env),
            hir::ExprKind::Concat(repeat, ref exprs) => {
                let mut bit_width = 0;
                for &expr in exprs {
                    let ty = cx.type_of(expr, env)?;
                    bit_width += bit_size_of_type(cx, ty, env)?;
                }
                let repeat = match repeat {
                    Some(repeat) => cx.constant_int_value_of(repeat, env)?.to_usize().unwrap(),
                    None => 1,
                };
                Ok(cx.mkty_int(repeat * bit_width))
            }
            hir::ExprKind::Cast(ty, _) => cx.map_to_type(ty, env),
            _ => {
                error!("{:#?}", hir);
                cx.unimp_msg("type analysis of", &hir)
            }
        },
        HirNode::ValueParam(p) => {
            if is_explicit_type(cx, p.ty)? {
                return cx.map_to_type(p.ty, env);
            }
            let env_data = cx.param_env_data(env);
            match env_data.find_value(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.type_of(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t.ty),
                _ => (),
            }
            if let Some(default) = p.default {
                return cx.type_of(default, env);
            }
            cx.emit(
                DiagBuilder2::error(format!(
                    "{} has implicit type but was not assigned and has no default",
                    p.desc_full()
                ))
                .span(p.human_span())
                .add_note("specify a type for the parameter; or")
                .add_note("add a default value for the parameter; or")
                .add_note("override the parameter from outside"),
            );
            Err(())
        }
        HirNode::VarDecl(d) => {
            if is_explicit_type(cx, d.ty)? {
                cx.map_to_type(d.ty, env)
            } else if let Some(init) = d.init {
                cx.type_of(init, env)
            } else {
                cx.emit(
                    DiagBuilder2::error(format!(
                        "{} has implicit type but is not initialized",
                        d.desc_full()
                    ))
                    .span(d.human_span())
                    .add_note("specify a type for the variable; or")
                    .add_note("add an initial value"),
                );
                Err(())
            }
        }
        HirNode::GenvarDecl(_) => Ok(cx.mkty_int(32)),
        HirNode::EnumVariant(v) => cx.map_to_type(v.enum_id, env),
        HirNode::Package(_) => Ok(cx.mkty_void()),
        _ => {
            error!("{:#?}", hir);
            cx.unimp_msg("type analysis of", &hir)
        }
    }
}

/// Convert a node to a type.
pub(crate) fn map_to_type<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Type(hir) => map_type_kind(cx, node_id, env, hir, &hir.kind),
        HirNode::TypeParam(param) => {
            let env_data = cx.param_env_data(env);
            match env_data.find_type(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.map_to_type(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t),
                _ => (),
            }
            if let Some(default) = param.default {
                return cx.map_to_type(default, env);
            }
            let mut d = DiagBuilder2::error(format!(
                "{} not assigned and has no default",
                param.desc_full(),
            ));
            let contexts = cx.param_env_contexts(env);
            for &context in &contexts {
                d = d.span(cx.span(context));
            }
            if contexts.is_empty() {
                d = d.span(param.human_span());
            }
            cx.emit(d);
            Err(())
        }
        HirNode::Typedef(def) => cx.map_to_type(def.ty, env),
        _ => cx.unimp_msg("conversion to type of", &hir),
    }
}

/// Check if a type (given by its node id) is explicit.
fn is_explicit_type<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<bool> {
    Ok(match cx.hir_of(node_id)? {
        HirNode::Type(x) => x.is_explicit(),
        _ => false,
    })
}

/// Map an HIR type into the type system.
///
/// This essentially converts `hir::TypeKind` to `Type`.
fn map_type_kind<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
    root: &hir::Type,
    kind: &hir::TypeKind,
) -> Result<Type<'gcx>> {
    #[allow(unreachable_patterns)]
    match *kind {
        hir::TypeKind::Builtin(hir::BuiltinType::Void) => Ok(cx.mkty_void()),
        hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_bit()),
        hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_logic()),
        hir::TypeKind::Builtin(hir::BuiltinType::Byte) => Ok(cx.mkty_int(8)),
        hir::TypeKind::Builtin(hir::BuiltinType::ShortInt) => Ok(cx.mkty_int(16)),
        hir::TypeKind::Builtin(hir::BuiltinType::Int) => Ok(cx.mkty_int(32)),
        hir::TypeKind::Builtin(hir::BuiltinType::LongInt) => Ok(cx.mkty_int(64)),
        hir::TypeKind::Named(name) => {
            let binding = cx.resolve_upwards_or_error(name, node_id)?;
            Ok(cx.mkty_named(name, (binding, env)))
        }
        hir::TypeKind::Scope(scope_id, name) => {
            let within = cx.resolve_node(scope_id, env)?;
            let binding = cx.resolve_downwards_or_error(name, within)?;
            Ok(cx.mkty_named(name, (binding, env)))
        }
        hir::TypeKind::Struct(..) => Ok(cx.mkty_struct(node_id)),
        hir::TypeKind::PackedArray(ref inner, lhs, rhs) => {
            let map_bound = |bound: NodeId| -> Result<&num::BigInt> {
                match cx.constant_value_of(bound, env)?.kind {
                    ValueKind::Int(ref int) => Ok(int),
                    _ => {
                        let span = cx.span(bound);
                        cx.emit(
                            DiagBuilder2::error(format!(
                                "array bound `{}` is not an integer",
                                span.extract()
                            ))
                            .span(span),
                        );
                        return Err(());
                    }
                }
            };
            let size: num::BigInt = (map_bound(lhs)? - map_bound(rhs)?).abs();
            let size = match size.to_usize() {
                Some(i) => i + 1,
                None => {
                    cx.emit(
                        DiagBuilder2::error(format!("{} is too large", kind.desc_full()))
                            .span(root.human_span())
                            .add_note(format!("array would contain {} elements", size)),
                    );
                    return Err(());
                }
            };
            match **inner {
                hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_int(size)),
                hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_integer(size)),
                _ => {
                    let inner_ty = map_type_kind(cx, node_id, env, root, inner)?;
                    Ok(cx.mkty_packed_array(size, inner_ty))
                }
            }
        }
        hir::TypeKind::Enum(ref variants, repr) => match repr {
            Some(repr) => cx.map_to_type(repr, env),
            None => Ok(cx.mkty_int(variants.len().next_power_of_two().trailing_zeros() as usize)),
        },
        // We should never request mapping of an implicit type. Rather, the
        // actual type should be mapped. Arriving here is a bug in the
        // calling function.
        hir::TypeKind::Implicit => unreachable!("implicit type not resolved"),
        _ => {
            error!("{:#?}", root);
            cx.unimp_msg("type analysis of", root)
        }
    }
}
<commit_msg>svlog: fix enum variant type<commit_after>// Copyright (c) 2016-2019 Fabian Schuiki

use crate::{
    crate_prelude::*,
    hir::HirNode,
    ty::{bit_size_of_type, Type, TypeKind},
    value::ValueKind,
    ParamEnv, ParamEnvBinding,
};
use num::traits::{cast::ToPrimitive, sign::Signed};

/// Determine the type of a node.
pub(crate) fn type_of<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Port(p) => cx.map_to_type(p.ty, env),
        HirNode::Expr(e) => match e.kind {
            hir::ExprKind::IntConst(width, _) => Ok(cx.mkty_int(width)),
            hir::ExprKind::UnsizedConst(_) => Ok(cx.mkty_int(1)),
            hir::ExprKind::TimeConst(_) => Ok(cx.mkty_time()),
            hir::ExprKind::Ident(_) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::Unary(op, arg) => {
                let arg_ty = cx.type_of(arg, env)?;
                Ok(match op {
                    hir::UnaryOp::Neg
                    | hir::UnaryOp::BitNot
                    | hir::UnaryOp::PreInc
                    | hir::UnaryOp::PreDec
                    | hir::UnaryOp::PostInc
                    | hir::UnaryOp::PostDec => arg_ty,
                    hir::UnaryOp::LogicNot => cx.mkty_bit(),
                    _ => {
                        error!("{:#?}", hir);
                        return cx.unimp_msg("type analysis of", &hir);
                    }
                })
            }
            hir::ExprKind::Binary(op, lhs, rhs) => {
                let lhs_ty = cx.type_of(lhs, env)?;
                let _rhs_ty = cx.type_of(rhs, env)?;
                Ok(match op {
                    hir::BinaryOp::Add
                    | hir::BinaryOp::Sub
                    | hir::BinaryOp::Mul
                    | hir::BinaryOp::Div
                    | hir::BinaryOp::Mod
                    | hir::BinaryOp::Pow
                    | hir::BinaryOp::LogicShL
                    | hir::BinaryOp::LogicShR
                    | hir::BinaryOp::ArithShL
                    | hir::BinaryOp::ArithShR
                    | hir::BinaryOp::BitAnd
                    | hir::BinaryOp::BitNand
                    | hir::BinaryOp::BitOr
                    | hir::BinaryOp::BitNor
                    | hir::BinaryOp::BitXor
                    | hir::BinaryOp::BitXnor => lhs_ty,
                    hir::BinaryOp::Eq
                    | hir::BinaryOp::Neq
                    | hir::BinaryOp::Lt
                    | hir::BinaryOp::Leq
                    | hir::BinaryOp::Gt
                    | hir::BinaryOp::Geq
                    | hir::BinaryOp::LogicAnd
                    | hir::BinaryOp::LogicOr => cx.mkty_bit(),
                    _ => {
                        error!("{:#?}", hir);
                        return cx.unimp_msg("type analysis of", &hir);
                    }
                })
            }
            hir::ExprKind::Field(..) => {
                let (_, _, field_id) = cx.resolve_field_access(node_id, env)?;
                cx.type_of(field_id, env)
            }
            hir::ExprKind::Index(target, mode) => {
                let target_ty = cx.type_of(target, env)?;
                match mode {
                    hir::IndexMode::One(..) => match *target_ty {
                        TypeKind::PackedArray(_, ty) => Ok(ty),
                        TypeKind::Int(_, ty::Domain::TwoValued) => Ok(cx.mkty_bit()),
                        TypeKind::Int(_, ty::Domain::FourValued) => Ok(cx.mkty_logic()),
                        _ => {
                            let hir = cx.hir_of(target)?;
                            cx.emit(
                                DiagBuilder2::error(format!(
                                    "{} cannot be indexed into",
                                    hir.desc_full()
                                ))
                                .span(hir.human_span()),
                            );
                            Err(())
                        }
                    },
                    hir::IndexMode::Many(..) => Ok(target_ty),
                }
            }
            hir::ExprKind::Builtin(hir::BuiltinCall::Clog2(_))
            | hir::ExprKind::Builtin(hir::BuiltinCall::Bits(_)) => Ok(cx.mkty_int(32)),
            hir::ExprKind::Builtin(hir::BuiltinCall::Signed(arg))
            | hir::ExprKind::Builtin(hir::BuiltinCall::Unsigned(arg)) => cx.type_of(arg, env),
            hir::ExprKind::Ternary(_cond, true_expr, _false_expr) => cx.type_of(true_expr, env),
            hir::ExprKind::Scope(..) => cx.type_of(cx.resolve_node(node_id, env)?, env),
            hir::ExprKind::PositionalPattern(..)
            | hir::ExprKind::NamedPattern(..)
            | hir::ExprKind::RepeatPattern(..)
            | hir::ExprKind::EmptyPattern => cx.type_of(cx.parent_node_id(node_id).unwrap(), env),
            hir::ExprKind::Concat(repeat, ref exprs) => {
                let mut bit_width = 0;
                for &expr in exprs {
                    let ty = cx.type_of(expr, env)?;
                    bit_width += bit_size_of_type(cx, ty, env)?;
                }
                let repeat = match repeat {
                    Some(repeat) => cx.constant_int_value_of(repeat, env)?.to_usize().unwrap(),
                    None => 1,
                };
                Ok(cx.mkty_int(repeat * bit_width))
            }
            hir::ExprKind::Cast(ty, _) => cx.map_to_type(ty, env),
            _ => {
                error!("{:#?}", hir);
                cx.unimp_msg("type analysis of", &hir)
            }
        },
        HirNode::ValueParam(p) => {
            if is_explicit_type(cx, p.ty)? {
                return cx.map_to_type(p.ty, env);
            }
            let env_data = cx.param_env_data(env);
            match env_data.find_value(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.type_of(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t.ty),
                _ => (),
            }
            if let Some(default) = p.default {
                return cx.type_of(default, env);
            }
            cx.emit(
                DiagBuilder2::error(format!(
                    "{} has implicit type but was not assigned and has no default",
                    p.desc_full()
                ))
                .span(p.human_span())
                .add_note("specify a type for the parameter; or")
                .add_note("add a default value for the parameter; or")
                .add_note("override the parameter from outside"),
            );
            Err(())
        }
        HirNode::VarDecl(d) => {
            if is_explicit_type(cx, d.ty)? {
                cx.map_to_type(d.ty, env)
            } else if let Some(init) = d.init {
                cx.type_of(init, env)
            } else {
                cx.emit(
                    DiagBuilder2::error(format!(
                        "{} has implicit type but is not initialized",
                        d.desc_full()
                    ))
                    .span(d.human_span())
                    .add_note("specify a type for the variable; or")
                    .add_note("add an initial value"),
                );
                Err(())
            }
        }
        HirNode::GenvarDecl(_) => Ok(cx.mkty_int(32)),
        HirNode::EnumVariant(v) => {
            // TODO: This is ultra hacky. The enum itself does not get its own
            // node ID, but rather shares this with the associated array dims.
            // So we nee to unpack those here again. This is horribly ugly and
            // should rather be done differently. E.g. by having the AST be more
            // of an ID-based graph.
            let hir = match cx.hir_of(v.enum_id)? {
                HirNode::Type(hir) => hir,
                _ => unreachable!(),
            };
            let mut kind = &hir.kind;
            loop {
                kind = match kind {
                    hir::TypeKind::PackedArray(ref inner, ..) => inner.as_ref(),
                    _ => break,
                }
            }
            map_type_kind(cx, v.enum_id, env, hir, kind)
        }
        HirNode::Package(_) => Ok(cx.mkty_void()),
        _ => {
            error!("{:#?}", hir);
            cx.unimp_msg("type analysis of", &hir)
        }
    }
}

/// Convert a node to a type.
pub(crate) fn map_to_type<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
) -> Result<Type<'gcx>> {
    let hir = cx.hir_of(node_id)?;
    #[allow(unreachable_patterns)]
    match hir {
        HirNode::Type(hir) => map_type_kind(cx, node_id, env, hir, &hir.kind),
        HirNode::TypeParam(param) => {
            let env_data = cx.param_env_data(env);
            match env_data.find_type(node_id) {
                Some(ParamEnvBinding::Indirect(assigned_id)) => {
                    return cx.map_to_type(assigned_id.0, assigned_id.1)
                }
                Some(ParamEnvBinding::Direct(t)) => return Ok(t),
                _ => (),
            }
            if let Some(default) = param.default {
                return cx.map_to_type(default, env);
            }
            let mut d = DiagBuilder2::error(format!(
                "{} not assigned and has no default",
                param.desc_full(),
            ));
            let contexts = cx.param_env_contexts(env);
            for &context in &contexts {
                d = d.span(cx.span(context));
            }
            if contexts.is_empty() {
                d = d.span(param.human_span());
            }
            cx.emit(d);
            Err(())
        }
        HirNode::Typedef(def) => cx.map_to_type(def.ty, env),
        _ => cx.unimp_msg("conversion to type of", &hir),
    }
}

/// Check if a type (given by its node id) is explicit.
fn is_explicit_type<'gcx>(cx: &impl Context<'gcx>, node_id: NodeId) -> Result<bool> {
    Ok(match cx.hir_of(node_id)? {
        HirNode::Type(x) => x.is_explicit(),
        _ => false,
    })
}

/// Map an HIR type into the type system.
///
/// This essentially converts `hir::TypeKind` to `Type`.
fn map_type_kind<'gcx>(
    cx: &impl Context<'gcx>,
    node_id: NodeId,
    env: ParamEnv,
    root: &hir::Type,
    kind: &hir::TypeKind,
) -> Result<Type<'gcx>> {
    #[allow(unreachable_patterns)]
    match *kind {
        hir::TypeKind::Builtin(hir::BuiltinType::Void) => Ok(cx.mkty_void()),
        hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_bit()),
        hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_logic()),
        hir::TypeKind::Builtin(hir::BuiltinType::Byte) => Ok(cx.mkty_int(8)),
        hir::TypeKind::Builtin(hir::BuiltinType::ShortInt) => Ok(cx.mkty_int(16)),
        hir::TypeKind::Builtin(hir::BuiltinType::Int) => Ok(cx.mkty_int(32)),
        hir::TypeKind::Builtin(hir::BuiltinType::LongInt) => Ok(cx.mkty_int(64)),
        hir::TypeKind::Named(name) => {
            let binding = cx.resolve_upwards_or_error(name, node_id)?;
            Ok(cx.mkty_named(name, (binding, env)))
        }
        hir::TypeKind::Scope(scope_id, name) => {
            let within = cx.resolve_node(scope_id, env)?;
            let binding = cx.resolve_downwards_or_error(name, within)?;
            Ok(cx.mkty_named(name, (binding, env)))
        }
        hir::TypeKind::Struct(..) => Ok(cx.mkty_struct(node_id)),
        hir::TypeKind::PackedArray(ref inner, lhs, rhs) => {
            let map_bound = |bound: NodeId| -> Result<&num::BigInt> {
                match cx.constant_value_of(bound, env)?.kind {
                    ValueKind::Int(ref int) => Ok(int),
                    _ => {
                        let span = cx.span(bound);
                        cx.emit(
                            DiagBuilder2::error(format!(
                                "array bound `{}` is not an integer",
                                span.extract()
                            ))
                            .span(span),
                        );
                        return Err(());
                    }
                }
            };
            let size: num::BigInt = (map_bound(lhs)? - map_bound(rhs)?).abs();
            let size = match size.to_usize() {
                Some(i) => i + 1,
                None => {
                    cx.emit(
                        DiagBuilder2::error(format!("{} is too large", kind.desc_full()))
                            .span(root.human_span())
                            .add_note(format!("array would contain {} elements", size)),
                    );
                    return Err(());
                }
            };
            match **inner {
                hir::TypeKind::Builtin(hir::BuiltinType::Bit) => Ok(cx.mkty_int(size)),
                hir::TypeKind::Builtin(hir::BuiltinType::Logic) => Ok(cx.mkty_integer(size)),
                _ => {
                    let inner_ty = map_type_kind(cx, node_id, env, root, inner)?;
                    Ok(cx.mkty_packed_array(size, inner_ty))
                }
            }
        }
        hir::TypeKind::Enum(ref variants, repr) => match repr {
            Some(repr) => cx.map_to_type(repr, env),
            None => Ok(cx.mkty_int(variants.len().next_power_of_two().trailing_zeros() as usize)),
        },
        // We should never request mapping of an implicit type. Rather, the
        // actual type should be mapped. Arriving here is a bug in the
        // calling function.
        hir::TypeKind::Implicit => unreachable!("implicit type not resolved"),
        _ => {
            error!("{:#?}", root);
            cx.unimp_msg("type analysis of", root)
        }
    }
}
<|endoftext|>