<commit_before>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

use crate::shell::SurfaceData;

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

// We implement Clone manually because #[derive(..)] would require R: Clone.
impl<R> Clone for Kind<R> {
    fn clone(&self) -> Self {
        match self {
            Kind::Xdg(xdg) => Kind::Xdg(xdg.clone()),
            Kind::Wl(wl) => Kind::Wl(wl.clone()),
        }
    }
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }

    /// Do this handle and the other one actually refer to the same toplevel surface?
    pub fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
            (Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
            _ => false,
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over this window and its children.
    ///
    /// Used for the fast path of the check in `matching`, and as the fall-back for the window
    /// geometry if that's not set explicitly.
    bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    fn matching(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        if !self.bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if data
                        .map(|data| data.contains_point(surface_local_point))
                        .unwrap_or(false)
                    {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update(&mut self, ctoken: CompositorToken<R>) {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Some((w, h)) = data.and_then(SurfaceData::size) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }

                        // Update the bounding box.
                        min_x = min_x.min(x);
                        min_y = min_y.min(y);
                        max_x = max_x.max(x + w);
                        max_y = max_y.max(y + h);

                        TraversalAction::DoChildren((x, y))
                    } else {
                        // If the parent surface is unmapped, then the child surfaces are hidden as
                        // well, no need to consider them here.
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self, ctoken: CompositorToken<R>) -> Rectangle {
        // It's the set geometry with the full bounding box as the fallback.
        ctoken
            .with_surface_data(self.toplevel.get_surface().unwrap(), |attributes| {
                attributes.user_data.get::<SurfaceData>().unwrap().geometry
            })
            .unwrap_or(self.bbox)
    }
}

pub struct WindowMap<R> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
}

impl<R> WindowMap<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }

    /// Finds the toplevel corresponding to the given `WlSurface`.
    pub fn find(&self, surface: &wl_surface::WlSurface) -> Option<Kind<R>> {
        self.windows.iter().find_map(|w| {
            if w.toplevel
                .get_surface()
                .map(|s| s.as_ref().equals(surface.as_ref()))
                .unwrap_or(false)
            {
                Some(w.toplevel.clone())
            } else {
                None
            }
        })
    }

    /// Returns the location of the toplevel, if it exists.
    pub fn location(&self, toplevel: &Kind<R>) -> Option<(i32, i32)> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.location)
    }

    /// Sets the location of the toplevel, if it exists.
    pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
        if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
            w.location = location;
            w.self_update(self.ctoken);
        }
    }

    /// Returns the geometry of the toplevel, if it exists.
    pub fn geometry(&self, toplevel: &Kind<R>) -> Option<Rectangle> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.geometry(self.ctoken))
    }
}
<commit_msg>anvil.window_map: add refresh_toplevel<commit_after>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

use crate::shell::SurfaceData;

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

// We implement Clone manually because #[derive(..)] would require R: Clone.
impl<R> Clone for Kind<R> {
    fn clone(&self) -> Self {
        match self {
            Kind::Xdg(xdg) => Kind::Xdg(xdg.clone()),
            Kind::Wl(wl) => Kind::Wl(wl.clone()),
        }
    }
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }

    /// Do this handle and the other one actually refer to the same toplevel surface?
    pub fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
            (Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
            _ => false,
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over this window and its children.
    ///
    /// Used for the fast path of the check in `matching`, and as the fall-back for the window
    /// geometry if that's not set explicitly.
    bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    fn matching(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        if !self.bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if data
                        .map(|data| data.contains_point(surface_local_point))
                        .unwrap_or(false)
                    {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update(&mut self, ctoken: CompositorToken<R>) {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    let data = attributes.user_data.get::<SurfaceData>();

                    if let Some((w, h)) = data.and_then(SurfaceData::size) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }

                        // Update the bounding box.
                        min_x = min_x.min(x);
                        min_y = min_y.min(y);
                        max_x = max_x.max(x + w);
                        max_y = max_y.max(y + h);

                        TraversalAction::DoChildren((x, y))
                    } else {
                        // If the parent surface is unmapped, then the child surfaces are hidden as
                        // well, no need to consider them here.
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self, ctoken: CompositorToken<R>) -> Rectangle {
        // It's the set geometry with the full bounding box as the fallback.
        ctoken
            .with_surface_data(self.toplevel.get_surface().unwrap(), |attributes| {
                attributes.user_data.get::<SurfaceData>().unwrap().geometry
            })
            .unwrap_or(self.bbox)
    }
}

pub struct WindowMap<R> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
}

impl<R> WindowMap<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken);
        }
    }

    /// Refreshes the state of the toplevel, if it exists.
    pub fn refresh_toplevel(&mut self, toplevel: &Kind<R>) {
        if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
            w.self_update(self.ctoken);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }

    /// Finds the toplevel corresponding to the given `WlSurface`.
    pub fn find(&self, surface: &wl_surface::WlSurface) -> Option<Kind<R>> {
        self.windows.iter().find_map(|w| {
            if w.toplevel
                .get_surface()
                .map(|s| s.as_ref().equals(surface.as_ref()))
                .unwrap_or(false)
            {
                Some(w.toplevel.clone())
            } else {
                None
            }
        })
    }

    /// Returns the location of the toplevel, if it exists.
    pub fn location(&self, toplevel: &Kind<R>) -> Option<(i32, i32)> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.location)
    }

    /// Sets the location of the toplevel, if it exists.
    pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
        if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
            w.location = location;
            w.self_update(self.ctoken);
        }
    }

    /// Returns the geometry of the toplevel, if it exists.
    pub fn geometry(&self, toplevel: &Kind<R>) -> Option<Rectangle> {
        self.windows
            .iter()
            .find(|w| w.toplevel.equals(toplevel))
            .map(|w| w.geometry(self.ctoken))
    }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;
use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use glium::backend::glutin_backend::GlutinFacade;
use glium::buffer::Content;
use glium::glutin::{ElementState, Event, VirtualKeyCode as KeyCode};
use glium::{self, Surface, VertexBuffer};

use graphics_gl::{TextBlitter, Vert2};
use input::Input;
use units::V2;

static BASIC_VRT: &'static str = include_str!("shaders/basic.v.glsl");
static BASIC_FRG: &'static str = include_str!("shaders/basic.f.glsl");

static MAX_VERTS: usize = 256;

/// Represents a mouse-input sample from some brush
struct ControlPoint {
    screen_xy: V2,
}

pub struct Engine {
    is_running: bool,

    context:    GlutinFacade,
    controller: Input,
}

impl Engine {
    pub fn new(gl_ctx: GlutinFacade) -> Engine {
        Engine {
            is_running: true,

            context:    gl_ctx,
            controller: Input::new(),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms = Duration::from_millis(1000 / 120); // TODO: const fn?
        let game_start_at = Instant::now();

        let mut frame_start_at;
        let mut elapsed_time;

        // draw a basic shape using standard shader
        let shape = vec![
            // face 1
            Vert2 { pos: [ 1.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0, -1.0, 0.0], color: [1.0, 0.0, 0.0] },
        ];

        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

        let mut vbuf_cursor = glium::VertexBuffer::new(&self.context, &shape[..])
            .ok().expect("could not alloc vbuf");

        let mut vbuf_points = glium::VertexBuffer::empty_dynamic(&self.context, MAX_VERTS)
            .ok().expect("could not alloc vbuf");

        let program = match glium::Program::from_source(&self.context, BASIC_VRT, BASIC_FRG, None) {
            Ok(program) => program,
            Err(msg) => panic!("could not load shader: {}", msg),
        };

        // current cursor state
        let mut cursor_x = 0;
        let mut cursor_y = 0;

        // control point buffers
        let mut input_buffers = vec![];
        let mut input_samples = LinkedList::new();
        let mut cursor_commit = true;
        let mut cursor_down   = false;

        // text renedring
        let text_blitter = TextBlitter::new(&mut self.context);
        let mut text_count  = 0;
        let mut frame_count = 0;
        let mut text_scale  = 0.0;

        while self.is_running {
            // cut new frame
            frame_start_at = Instant::now();
            self.controller.begin_new_frame();

            // process platform events
            for evt in self.context.poll_events() {
                match evt {
                    Event::Closed => self.is_running = false,
                    Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                        self.controller.key_down_event(key);
                    },

                    Event::KeyboardInput(ElementState::Released, _, Some(key)) => {
                        self.controller.key_up_event(key);
                    },

                    Event::MouseInput(ElementState::Pressed,  _)  => {
                        cursor_down = true;
                        cursor_commit = false;
                    },

                    Event::MouseInput(ElementState::Released, _)  => cursor_down = false,

                    Event::MouseMoved(x,y) => { cursor_x = x; cursor_y = y },

                    _ => (),
                }
            }

            // TODO: (?) deduplicate input against last input?
            // store user input into control point buffers
            let (wx, wy) = Engine::world_to_unit(cursor_x as f64, cursor_y as f64);
            if cursor_down {
                input_samples.push_front(ControlPoint {
                    screen_xy: V2(cursor_x as i64, cursor_y as i64),
                });
            } else if !cursor_down && !cursor_commit {
                // swap the input buffer with a fresh one
                let mut input_buf = LinkedList::new();
                mem::swap(&mut input_samples, &mut input_buf);

                // commit the dirty one to heap
                input_buffers.push(input_buf);
                cursor_commit = true;
            }

            if self.controller.was_key_pressed(KeyCode::Escape) {
                self.is_running = false;
            }

            if self.controller.was_key_pressed(KeyCode::Up) {
                text_scale += 0.05;
            } else if self.controller.was_key_pressed(KeyCode::Down) {
                text_scale -= 0.05;
            }

            // composite frame
            let mut target = self.context.draw();
            target.clear_color(0.05, 0.05, 0.05, 1.0);

            let tri_params = glium::DrawParameters {
                .. Default::default()
            };

            let mut time_ms = 0.0;
            let time = Instant::now().duration_since(game_start_at);
            time_ms += time.as_secs() as f64 * 1000.0;
            time_ms += time.subsec_nanos() as f64 * 0.001 * 0.001;

            frame_count += 1;
            if frame_count > 10 {
                frame_count = 0;
                text_count = (text_count + 1) % 0xFF;
            }

            // TODO: helper for this
            // strlen =>  (char width * text length) * scale
            let text_out = format!("debug mode 0x{:02X}", text_count);

            // the text size is
            // (why /128 and not /256 ???)
            // char width: 16 * (aspect correction) / 128
            // * num chars
            // * scale of text
            //
            let strlen =
                ((16.0 * (720.0 / 1280.0)) / 128.0)
                * text_out.len() as f32
                * text_scale;

                // ((16.0 / 128.0) * text_out.len() as f32) * text_scale;
            text_blitter.draw(&text_out[..], text_scale, (1.0 - strlen, 1.0), &mut target);

            // draw cursor
            let cursor_uni = uniform! {
                ofs:   [wx as f32, wy as f32, 0.0f32],
                scale: 0.15f32,
                timer: time_ms as f32 * 0.001,
            };

            target.draw(&vbuf_cursor, &indices, &program, &cursor_uni, &tri_params)
                .ok().expect("could not blit cursor example");

            // draw control points
            {
                // vbuf.invalidate();
                let mut writer = vbuf_points.map_write();
                writer.set(0, Vert2 { pos: [-1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(1, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(2, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });

                writer.set(3, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(4, Vert2 { pos: [ 1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(5, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
            }

            // for each path draw control point there
            for path in input_buffers.iter() {
                // inflate each control point to six verts
                for point in path.iter() {
                    let (wx, wy) = Engine::world_to_unit(point.screen_xy.0 as f64,
                                                         point.screen_xy.1 as f64);

                    let path_uni = uniform! {
                        ofs:   [wx as f32, wy as f32, 0.0f32],
                        scale: 0.05f32,
                        timer: time_ms as f32 * 0.001,
                    };

                    target.draw(&vbuf_points, &indices, &program, &path_uni, &tri_params)
                        .ok().expect("could not blit cursor example");
                }
            }

            target.finish()
                .ok().expect("could not render frame");

            // sleep for a bit if we made our deadline
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn world_to_unit(x: f64, y: f64) -> (f64, f64) {
        let adj_x = x / 640.0;
        let adj_y = y / 360.0;
        ( (adj_x - 1.0), -(adj_y - 1.0) )
    }
}
<commit_msg>blit the current sample buffer as well<commit_after>use std::collections::LinkedList;
use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use glium::backend::glutin_backend::GlutinFacade;
use glium::buffer::Content;
use glium::glutin::{ElementState, Event, VirtualKeyCode as KeyCode};
use glium::{self, Surface, VertexBuffer};

use graphics_gl::{TextBlitter, Vert2};
use input::Input;
use units::V2;

static BASIC_VRT: &'static str = include_str!("shaders/basic.v.glsl");
static BASIC_FRG: &'static str = include_str!("shaders/basic.f.glsl");

static MAX_VERTS: usize = 256;

/// Represents a mouse-input sample from some brush
struct ControlPoint {
    screen_xy: V2,
}

pub struct Engine {
    is_running: bool,

    context:    GlutinFacade,
    controller: Input,
}

impl Engine {
    pub fn new(gl_ctx: GlutinFacade) -> Engine {
        Engine {
            is_running: true,

            context:    gl_ctx,
            controller: Input::new(),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms = Duration::from_millis(1000 / 120); // TODO: const fn?
        let game_start_at = Instant::now();

        let mut frame_start_at;
        let mut elapsed_time;

        // draw a basic shape using standard shader
        let shape = vec![
            // face 1
            Vert2 { pos: [ 1.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0, -1.0, 0.0], color: [1.0, 0.0, 0.0] },
        ];

        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

        let mut vbuf_cursor = glium::VertexBuffer::new(&self.context, &shape[..])
            .ok().expect("could not alloc vbuf");

        let mut vbuf_points = glium::VertexBuffer::empty_dynamic(&self.context, MAX_VERTS)
            .ok().expect("could not alloc vbuf");

        let program = match glium::Program::from_source(&self.context, BASIC_VRT, BASIC_FRG, None) {
            Ok(program) => program,
            Err(msg) => panic!("could not load shader: {}", msg),
        };

        // current cursor state
        let mut cursor_x = 0;
        let mut cursor_y = 0;

        // control point buffers
        let mut input_buffers = vec![];
        let mut input_samples = LinkedList::new();
        let mut cursor_commit = true;
        let mut cursor_down   = false;

        // text renedring
        let text_blitter = TextBlitter::new(&mut self.context);
        let mut text_count  = 0;
        let mut frame_count = 0;
        let mut text_scale  = 0.0;

        while self.is_running {
            // cut new frame
            frame_start_at = Instant::now();
            self.controller.begin_new_frame();

            // process platform events
            for evt in self.context.poll_events() {
                match evt {
                    Event::Closed => self.is_running = false,
                    Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                        self.controller.key_down_event(key);
                    },

                    Event::KeyboardInput(ElementState::Released, _, Some(key)) => {
                        self.controller.key_up_event(key);
                    },

                    Event::MouseInput(ElementState::Pressed,  _)  => {
                        cursor_down = true;
                        cursor_commit = false;
                    },

                    Event::MouseInput(ElementState::Released, _)  => cursor_down = false,

                    Event::MouseMoved(x,y) => { cursor_x = x; cursor_y = y },

                    _ => (),
                }
            }

            // TODO: (?) deduplicate input against last input?
            // store user input into control point buffers
            let (wx, wy) = Engine::world_to_unit(cursor_x as f64, cursor_y as f64);
            if cursor_down {
                input_samples.push_front(ControlPoint {
                    screen_xy: V2(cursor_x as i64, cursor_y as i64),
                });
            } else if !cursor_down && !cursor_commit {
                // swap the input buffer with a fresh one
                let mut input_buf = LinkedList::new();
                mem::swap(&mut input_samples, &mut input_buf);

                // commit the dirty one to heap
                input_buffers.push(input_buf);
                cursor_commit = true;
            }

            if self.controller.was_key_pressed(KeyCode::Escape) {
                self.is_running = false;
            }

            if self.controller.was_key_pressed(KeyCode::Up) {
                text_scale += 0.05;
            } else if self.controller.was_key_pressed(KeyCode::Down) {
                text_scale -= 0.05;
            }

            // composite frame
            let mut target = self.context.draw();
            target.clear_color(0.05, 0.05, 0.05, 1.0);

            let tri_params = glium::DrawParameters {
                .. Default::default()
            };

            let mut time_ms = 0.0;
            let time = Instant::now().duration_since(game_start_at);
            time_ms += time.as_secs() as f64 * 1000.0;
            time_ms += time.subsec_nanos() as f64 * 0.001 * 0.001;

            frame_count += 1;
            if frame_count > 10 {
                frame_count = 0;
                text_count = (text_count + 1) % 0xFF;
            }

            // TODO: helper for this
            // strlen =>  (char width * text length) * scale
            let text_out = format!("debug mode 0x{:02X}", text_count);

            // the text size is
            // (why /128 and not /256 ???)
            // char width: 16 * (aspect correction) / 128
            // * num chars
            // * scale of text
            //
            let strlen =
                ((16.0 * (720.0 / 1280.0)) / 128.0)
                * text_out.len() as f32
                * text_scale;

                // ((16.0 / 128.0) * text_out.len() as f32) * text_scale;
            text_blitter.draw(&text_out[..], text_scale, (1.0 - strlen, 1.0), &mut target);

            // draw cursor
            let cursor_uni = uniform! {
                ofs:   [wx as f32, wy as f32, 0.0f32],
                scale: 0.15f32,
                timer: time_ms as f32 * 0.001,
            };

            target.draw(&vbuf_cursor, &indices, &program, &cursor_uni, &tri_params)
                .ok().expect("could not blit cursor example");

            // draw control points
            {
                // vbuf.invalidate();
                let mut writer = vbuf_points.map_write();
                writer.set(0, Vert2 { pos: [-1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(1, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(2, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });

                writer.set(3, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(4, Vert2 { pos: [ 1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(5, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
            }

            // inflate each control point to six verts
            for point in input_samples.iter() {
                let (wx, wy) = Engine::world_to_unit(point.screen_xy.0 as f64,
                                                     point.screen_xy.1 as f64);

                let path_uni = uniform! {
                    ofs:   [wx as f32, wy as f32, 0.0f32],
                    scale: 0.05f32,
                    timer: time_ms as f32 * 0.001,
                };

                target.draw(&vbuf_points, &indices, &program, &path_uni, &tri_params)
                    .ok().expect("could not blit cursor example");
            }

            // for each path draw control point there
            for path in input_buffers.iter() {
                // inflate each control point to six verts
                for point in path.iter() {
                    let (wx, wy) = Engine::world_to_unit(point.screen_xy.0 as f64,
                                                         point.screen_xy.1 as f64);

                    let path_uni = uniform! {
                        ofs:   [wx as f32, wy as f32, 0.0f32],
                        scale: 0.05f32,
                        timer: time_ms as f32 * 0.001,
                    };

                    target.draw(&vbuf_points, &indices, &program, &path_uni, &tri_params)
                        .ok().expect("could not blit cursor example");
                }
            }

            target.finish()
                .ok().expect("could not render frame");

            // sleep for a bit if we made our deadline
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn world_to_unit(x: f64, y: f64) -> (f64, f64) {
        let adj_x = x / 640.0;
        let adj_y = y / 360.0;
        ( (adj_x - 1.0), -(adj_y - 1.0) )
    }
}
<|endoftext|>


<commit_before>
use prelude::*;

use visit::{
    GraphBase,
    IntoNeighbors,
    IntoNeighborsDirected,
    NodeIndexable,
    Visitable,
};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    fn include_node(&self, node: N) -> bool { let _ = node; true }
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// A filtered adaptor of a graph.
#[derive(Copy, Clone, Debug)]
pub struct Filtered<G, F>(pub G, pub F);

impl<G, F> GraphBase for Filtered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a Filtered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = FilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        FilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct FilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for FilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            (&mut self.iter).filter(move |&target| f.include_node(target)).next()
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a Filtered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = FilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        FilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<G, F> Visitable for Filtered<G, F>
    where G: Visitable,
{
    type Map = G::Map;
    fn visit_map(&self) -> G::Map {
        self.0.visit_map()
    }
    fn reset_map(&self, map: &mut Self::Map) {
        self.0.reset_map(map);
    }
}

impl<G, F> NodeIndexable for Filtered<G, F>
    where G: NodeIndexable,
{
    fn node_bound(&self) -> usize { self.0.node_bound() }
    fn to_index(n: G::NodeId) -> usize { G::to_index(n) }
}
<commit_msg>Implement FilterNode for certain visit maps<commit_after>
use prelude::*;

use fixedbitset::FixedBitSet;
use std::collections::HashSet;

use visit::{
    GraphBase,
    IntoNeighbors,
    IntoNeighborsDirected,
    NodeIndexable,
    Visitable,
    VisitMap,
};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    fn include_node(&self, node: N) -> bool { let _ = node; true }
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
    where FixedBitSet: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
    where HashSet<N, S>: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// A filtered adaptor of a graph.
#[derive(Copy, Clone, Debug)]
pub struct Filtered<G, F>(pub G, pub F);

impl<G, F> GraphBase for Filtered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a Filtered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = FilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        FilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct FilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for FilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            (&mut self.iter).filter(move |&target| f.include_node(target)).next()
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a Filtered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = FilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        FilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<G, F> Visitable for Filtered<G, F>
    where G: Visitable,
{
    type Map = G::Map;
    fn visit_map(&self) -> G::Map {
        self.0.visit_map()
    }
    fn reset_map(&self, map: &mut Self::Map) {
        self.0.reset_map(map);
    }
}

impl<G, F> NodeIndexable for Filtered<G, F>
    where G: NodeIndexable,
{
    fn node_bound(&self) -> usize { self.0.node_bound() }
    fn to_index(n: G::NodeId) -> usize { G::to_index(n) }
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::fmt;

use http::{request::Parts, Method, Request as HttpRequest};
use url::Url;
#[cfg(feature = "json")]
use serde_json;
use serde::Serialize;
use serde_urlencoded;

use super::{Body, Client, Response};
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};

/// A request which can be executed with `Client::execute()`.
pub struct Request {
    method: Method,
    url: Url,
    headers: HeaderMap,
    body: Option<Body>,
    pub(super) cors: bool,
}

/// A builder to construct the properties of a `Request`.
pub struct RequestBuilder {
    client: Client,
    request: crate::Result<Request>,
}

impl Request {
    pub(super) fn new(method: Method, url: Url) -> Self {
        Request {
            method,
            url,
            headers: HeaderMap::new(),
            body: None,
            cors: true,
        }
    }

    /// Get the method.
    #[inline]
    pub fn method(&self) -> &Method {
        &self.method
    }

    /// Get a mutable reference to the method.
    #[inline]
    pub fn method_mut(&mut self) -> &mut Method {
        &mut self.method
    }

    /// Get the url.
    #[inline]
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Get a mutable reference to the url.
    #[inline]
    pub fn url_mut(&mut self) -> &mut Url {
        &mut self.url
    }

    /// Get the headers.
    #[inline]
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Get a mutable reference to the headers.
    #[inline]
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Get the body.
    #[inline]
    pub fn body(&self) -> Option<&Body> {
        self.body.as_ref()
    }

    /// Get a mutable reference to the body.
    #[inline]
    pub fn body_mut(&mut self) -> &mut Option<Body> {
        &mut self.body
    }
}

impl RequestBuilder {
    pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
        RequestBuilder { client, request }
    }

    /// Modify the query string of the URL.
    ///
    /// Modifies the URL of this request, adding the parameters provided.
    /// This method appends and does not overwrite. This means that it can
    /// be called multiple times and that existing query parameters are not
    /// overwritten if the same key is used. The key will simply show up
    /// twice in the query string.
    /// Calling `.query([("foo", "a"), ("foo", "b")])` gives `"foo=a&foo=b"`.
    ///
    /// # Note
    /// This method does not support serializing a single key-value
    /// pair. Instead of using `.query(("key", "val"))`, use a sequence, such
    /// as `.query(&[("key", "val")])`. It's also possible to serialize structs
    /// and maps into a key-value pair.
    ///
    /// # Errors
    /// This method will fail if the object you provide cannot be serialized
    /// into a query string.
    pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            let url = req.url_mut();
            let mut pairs = url.query_pairs_mut();
            let serializer = serde_urlencoded::Serializer::new(&mut pairs);

            if let Err(err) = query.serialize(serializer) {
                error = Some(crate::error::builder(err));
            }
        }
        if let Ok(ref mut req) = self.request {
            if let Some("") = req.url().query() {
                req.url_mut().set_query(None);
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Send a form body.
    pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match serde_urlencoded::to_string(form) {
                Ok(body) => {
                    req.headers_mut().insert(
                        CONTENT_TYPE,
                        HeaderValue::from_static("application/x-www-form-urlencoded"),
                    );
                    *req.body_mut() = Some(body.into());
                }
                Err(err) => error = Some(crate::error::builder(err)),
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    #[cfg(feature = "json")]
    /// Set the request json
    pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match serde_json::to_vec(json) {
                Ok(body) => {
                    req.headers_mut()
                        .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
                    *req.body_mut() = Some(body.into());
                }
                Err(err) => error = Some(crate::error::builder(err)),
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Enable HTTP bearer authentication.
    pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
    where
        T: fmt::Display,
    {
        let header_value = format!("Bearer {}", token);
        self.header(crate::header::AUTHORIZATION, header_value)
    }

    /// Set the request body.
    pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            req.body = Some(body.into());
        }
        self
    }

    /// TODO
    pub fn multipart(mut self, multipart: super::multipart::Form) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            *req.body_mut() = Some(Body::from_form(multipart))
        }
        self
    }

    /// Add a `Header` to this Request.
    pub fn header<K, V>(mut self, key: K, value: V) -> RequestBuilder
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
    {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match <HeaderName as TryFrom<K>>::try_from(key) {
                Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
                    Ok(value) => {
                        req.headers_mut().append(key, value);
                    }
                    Err(e) => error = Some(crate::error::builder(e.into())),
                },
                Err(e) => error = Some(crate::error::builder(e.into())),
            };
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Add a set of Headers to the existing ones on this Request.
    ///
    /// The headers will be merged in to any already set.
    pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            crate::util::replace_headers(req.headers_mut(), headers);
        }
        self
    }

    /// Disable CORS on fetching the request.
    ///
    /// # WASM
    ///
    /// This option is only effective with WebAssembly target.
    ///
    /// The [request mode][mdn] will be set to 'no-cors'.
    ///
    /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
    pub fn fetch_mode_no_cors(mut self) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            req.cors = false;
        }
        self
    }

    /// Constructs the Request and sends it to the target URL, returning a
    /// future Response.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use reqwest::Error;
    /// #
    /// # async fn run() -> Result<(), Error> {
    /// let response = reqwest::Client::new()
    ///     .get("https://hyper.rs")
    ///     .send()
    ///     .await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn send(self) -> crate::Result<Response> {
        let req = self.request?;
        self.client.execute_request(req).await
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
    }
}

impl fmt::Debug for RequestBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut builder = f.debug_struct("RequestBuilder");
        match self.request {
            Ok(ref req) => fmt_request_fields(&mut builder, req).finish(),
            Err(ref err) => builder.field("error", err).finish(),
        }
    }
}

fn fmt_request_fields<'a, 'b>(
    f: &'a mut fmt::DebugStruct<'a, 'b>,
    req: &Request,
) -> &'a mut fmt::DebugStruct<'a, 'b> {
    f.field("method", &req.method)
        .field("url", &req.url)
        .field("headers", &req.headers)
}

impl<T> TryFrom<HttpRequest<T>> for Request
where
    T: Into<Body>,
{
    type Error = crate::Error;

    fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
        let (parts, body) = req.into_parts();
        let Parts {
            method,
            uri,
            headers,
            ..
        } = parts;
        let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
        Ok(Request {
            method,
            url,
            headers,
            body: Some(body.into()),
            cors: true,
        })
    }
}
<commit_msg>Introduce `build` method on WASM RequestBuilder for compatibility with async_impl (#1019)<commit_after>use std::convert::TryFrom;
use std::fmt;

use http::{request::Parts, Method, Request as HttpRequest};
use url::Url;
#[cfg(feature = "json")]
use serde_json;
use serde::Serialize;
use serde_urlencoded;

use super::{Body, Client, Response};
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};

/// A request which can be executed with `Client::execute()`.
pub struct Request {
    method: Method,
    url: Url,
    headers: HeaderMap,
    body: Option<Body>,
    pub(super) cors: bool,
}

/// A builder to construct the properties of a `Request`.
pub struct RequestBuilder {
    client: Client,
    request: crate::Result<Request>,
}

impl Request {
    pub(super) fn new(method: Method, url: Url) -> Self {
        Request {
            method,
            url,
            headers: HeaderMap::new(),
            body: None,
            cors: true,
        }
    }

    /// Get the method.
    #[inline]
    pub fn method(&self) -> &Method {
        &self.method
    }

    /// Get a mutable reference to the method.
    #[inline]
    pub fn method_mut(&mut self) -> &mut Method {
        &mut self.method
    }

    /// Get the url.
    #[inline]
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Get a mutable reference to the url.
    #[inline]
    pub fn url_mut(&mut self) -> &mut Url {
        &mut self.url
    }

    /// Get the headers.
    #[inline]
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Get a mutable reference to the headers.
    #[inline]
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Get the body.
    #[inline]
    pub fn body(&self) -> Option<&Body> {
        self.body.as_ref()
    }

    /// Get a mutable reference to the body.
    #[inline]
    pub fn body_mut(&mut self) -> &mut Option<Body> {
        &mut self.body
    }
}

impl RequestBuilder {
    pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
        RequestBuilder { client, request }
    }

    /// Modify the query string of the URL.
    ///
    /// Modifies the URL of this request, adding the parameters provided.
    /// This method appends and does not overwrite. This means that it can
    /// be called multiple times and that existing query parameters are not
    /// overwritten if the same key is used. The key will simply show up
    /// twice in the query string.
    /// Calling `.query([("foo", "a"), ("foo", "b")])` gives `"foo=a&foo=b"`.
    ///
    /// # Note
    /// This method does not support serializing a single key-value
    /// pair. Instead of using `.query(("key", "val"))`, use a sequence, such
    /// as `.query(&[("key", "val")])`. It's also possible to serialize structs
    /// and maps into a key-value pair.
    ///
    /// # Errors
    /// This method will fail if the object you provide cannot be serialized
    /// into a query string.
    pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            let url = req.url_mut();
            let mut pairs = url.query_pairs_mut();
            let serializer = serde_urlencoded::Serializer::new(&mut pairs);

            if let Err(err) = query.serialize(serializer) {
                error = Some(crate::error::builder(err));
            }
        }
        if let Ok(ref mut req) = self.request {
            if let Some("") = req.url().query() {
                req.url_mut().set_query(None);
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Send a form body.
    pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match serde_urlencoded::to_string(form) {
                Ok(body) => {
                    req.headers_mut().insert(
                        CONTENT_TYPE,
                        HeaderValue::from_static("application/x-www-form-urlencoded"),
                    );
                    *req.body_mut() = Some(body.into());
                }
                Err(err) => error = Some(crate::error::builder(err)),
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    #[cfg(feature = "json")]
    /// Set the request json
    pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match serde_json::to_vec(json) {
                Ok(body) => {
                    req.headers_mut()
                        .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
                    *req.body_mut() = Some(body.into());
                }
                Err(err) => error = Some(crate::error::builder(err)),
            }
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Enable HTTP bearer authentication.
    pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
    where
        T: fmt::Display,
    {
        let header_value = format!("Bearer {}", token);
        self.header(crate::header::AUTHORIZATION, header_value)
    }

    /// Set the request body.
    pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            req.body = Some(body.into());
        }
        self
    }

    /// TODO
    pub fn multipart(mut self, multipart: super::multipart::Form) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            *req.body_mut() = Some(Body::from_form(multipart))
        }
        self
    }

    /// Add a `Header` to this Request.
    pub fn header<K, V>(mut self, key: K, value: V) -> RequestBuilder
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
    {
        let mut error = None;
        if let Ok(ref mut req) = self.request {
            match <HeaderName as TryFrom<K>>::try_from(key) {
                Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
                    Ok(value) => {
                        req.headers_mut().append(key, value);
                    }
                    Err(e) => error = Some(crate::error::builder(e.into())),
                },
                Err(e) => error = Some(crate::error::builder(e.into())),
            };
        }
        if let Some(err) = error {
            self.request = Err(err);
        }
        self
    }

    /// Add a set of Headers to the existing ones on this Request.
    ///
    /// The headers will be merged in to any already set.
    pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            crate::util::replace_headers(req.headers_mut(), headers);
        }
        self
    }

    /// Disable CORS on fetching the request.
    ///
    /// # WASM
    ///
    /// This option is only effective with WebAssembly target.
    ///
    /// The [request mode][mdn] will be set to 'no-cors'.
    ///
    /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
    pub fn fetch_mode_no_cors(mut self) -> RequestBuilder {
        if let Ok(ref mut req) = self.request {
            req.cors = false;
        }
        self
    }

    /// Build a `Request`, which can be inspected, modified and executed with
    /// `Client::execute()`.
    pub fn build(self) -> crate::Result<Request> {
        self.request
    }

    /// Constructs the Request and sends it to the target URL, returning a
    /// future Response.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use reqwest::Error;
    /// #
    /// # async fn run() -> Result<(), Error> {
    /// let response = reqwest::Client::new()
    ///     .get("https://hyper.rs")
    ///     .send()
    ///     .await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn send(self) -> crate::Result<Response> {
        let req = self.request?;
        self.client.execute_request(req).await
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
    }
}

impl fmt::Debug for RequestBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut builder = f.debug_struct("RequestBuilder");
        match self.request {
            Ok(ref req) => fmt_request_fields(&mut builder, req).finish(),
            Err(ref err) => builder.field("error", err).finish(),
        }
    }
}

fn fmt_request_fields<'a, 'b>(
    f: &'a mut fmt::DebugStruct<'a, 'b>,
    req: &Request,
) -> &'a mut fmt::DebugStruct<'a, 'b> {
    f.field("method", &req.method)
        .field("url", &req.url)
        .field("headers", &req.headers)
}

impl<T> TryFrom<HttpRequest<T>> for Request
where
    T: Into<Body>,
{
    type Error = crate::Error;

    fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
        let (parts, body) = req.into_parts();
        let Parts {
            method,
            uri,
            headers,
            ..
        } = parts;
        let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
        Ok(Request {
            method,
            url,
            headers,
            body: Some(body.into()),
            cors: true,
        })
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit="128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate base_x;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use proc_macro::TokenStream;

#[derive(Clone, Serialize, Deserialize, Debug)]
enum TypeMetadata {
    I32,
    F64,
    Custom {
        name: Option< String >,
        conversion_fn: String
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
struct ArgMetadata {
    name: String,
    ty: TypeMetadata
}

#[derive(Clone, Serialize, Deserialize, Debug)]
struct ExportMetadata {
    name: String,
    args: Vec< ArgMetadata >,
    result: Option< TypeMetadata >
}

// This is a base62 encoding which consists of only alpha-numeric characters.
// Generated with: (('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a).join("")
const ENCODING_BASE: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

fn match_shallow_path( path: &syn::Path ) -> Option< &str > {
    if path.leading_colon.is_some() || path.segments.len() != 1 {
        return None;
    }

    let segment = &path.segments[ 0 ];
    match &segment.arguments {
        &syn::PathArguments::None => {},
        _ => return None
    }

    Some( segment.ident.as_ref() )
}

fn match_type( ty: &syn::Type ) -> ExportType {
    match ty {
        &syn::Type::Reference( ref ty ) => {
            assert!( ty.mutability.is_none(), "`mut` bindings are not supported" );
            match *ty.elem {
                syn::Type::Path( ref path ) if match_shallow_path( &path.path ).map( |path| path == "str" ).unwrap_or( false ) => {
                    ExportType::StrRef
                },
                syn::Type::Slice( ref slice ) => {
                    ExportType::Slice( (*slice.elem).clone() )
                },
                ref elem => ExportType::UnknownRef( elem.clone() )
            }
        },
        &syn::Type::Path( ref path ) => {
            let name = match match_shallow_path( &path.path ) {
                Some( name ) => name,
                None => return ExportType::Unknown( ty.clone() )
            };

            match name {
                "i32" => ExportType::I32,
                "f64" => ExportType::F64,
                _ => ExportType::Unknown( ty.clone() )
            }
        },
        &syn::Type::Tuple( ref tuple ) if tuple.elems.is_empty() => ExportType::Unit,
        _ => ExportType::Unknown( ty.clone() )
    }
}

enum ExportType {
    Unit,
    I32,
    F64,
    StrRef,
    Slice( syn::Type ),
    Unknown( syn::Type ),
    UnknownRef( syn::Type )
}

struct ExportArg {
    ident: syn::Ident,
    ty: ExportType
}

struct Export {
    ident: syn::Ident,
    return_ty: ExportType,
    args: Vec< ExportArg >
}

fn process( exports: Vec< Export > ) -> quote::Tokens {
    let mut output = Vec::new();
    for export in exports {
        let export_result;
        let export_result_conversion;
        let export_result_metadata;
        let mut export_args = Vec::new();
        let mut export_args_metadata = Vec::new();
        let mut export_args_idents = Vec::new();
        let mut export_args_conversions = Vec::new();

        match export.return_ty {
            ExportType::Unit => {
                export_result = quote! { () };
                export_result_conversion = quote! {};
                export_result_metadata = None;
            },
            ExportType::I32 => {
                export_result = quote! { i32 };
                export_result_conversion = quote! {};
                export_result_metadata = Some( TypeMetadata::I32 );
            },
            ExportType::F64 => {
                export_result = quote! { f64 };
                export_result_conversion = quote! {};
                export_result_metadata = Some( TypeMetadata::F64 );
            },
            ExportType::Unknown( _ ) |
            ExportType::UnknownRef( _ ) |
            ExportType::StrRef |
            ExportType::Slice( _ ) => {
                // TODO: For known types generate more efficient serialization.
                export_result = quote! { () };
                // TODO: Figure out a better way to do this, if possible.
                export_result_conversion = quote! {
                    let __result = ::stdweb::private::IntoNewtype::into_newtype( __result );
                    let __result_memory_required = ::stdweb::private::JsSerializeOwned::memory_required_owned( &__result );
                    let mut __result_arena = ::stdweb::private::PreallocatedArena::new( __result_memory_required );
                    let mut __result = Some( __result );
                    let __result = ::stdweb::private::JsSerializeOwned::into_js_owned( &mut __result, &mut __result_arena );
                    let __result = &__result as *const _;
                    __js_raw_asm!( "Module.STDWEB_PRIVATE.tmp = Module.STDWEB_PRIVATE.to_js( $0 );", __result );
                    let __result = ();
                };
                export_result_metadata = Some( TypeMetadata::Custom {
                    name: None,
                    conversion_fn: "Module.STDWEB_PRIVATE.acquire_tmp".to_owned()
                });
            }
        }

        for arg in &export.args {
            let export_arg_ident = arg.ident.clone();
            let export_arg_ty;
            let export_arg_ty_metadata;
            match arg.ty {
                ExportType::I32 => {
                    export_arg_ty = quote! { i32 };
                    export_arg_ty_metadata = TypeMetadata::I32;
                },
                ExportType::F64 => {
                    export_arg_ty = quote! { f64 };
                    export_arg_ty_metadata = TypeMetadata::F64;
                },
                ExportType::Unit => {
                    panic!( "Receiving arguments of type `()` isn't supported" );
                },
                ExportType::Unknown( _ ) |
                ExportType::UnknownRef( _ ) |
                ExportType::StrRef |
                ExportType::Slice( _ ) => {
                    // TODO: For known types generate more efficient serialization.
                    export_arg_ty = quote! { i32 };
                    export_args_conversions.push( quote! {
                        let #export_arg_ident = {
                            let pointer = #export_arg_ident as *mut ::stdweb::private::SerializedValue;
                            unsafe {
                                let value = (&*pointer).deserialize();
                                ::stdweb::private::__web_free( pointer as *mut u8, ::std::mem::size_of::< ::stdweb::private::SerializedValue >() );
                                value
                            }
                        };
                    });

                    export_arg_ty_metadata = TypeMetadata::Custom {
                        name: None,
                        conversion_fn: "Module.STDWEB_PRIVATE.prepare_any_arg".to_owned()
                    };
                }
            }

            export_args_idents.push( export_arg_ident.clone() );
            export_args_metadata.push( ArgMetadata {
                name: format!( "{}", export_arg_ident ),
                ty: export_arg_ty_metadata
            });
            export_args.push( quote! {
                #export_arg_ident: #export_arg_ty
            });
        }

        for arg in &export.args {
            let export_arg_ident = arg.ident.clone();
            match arg.ty {
                // TODO: Throw a JS exception if `try_into` fails.
                ExportType::Unknown( ref ty ) => {
                    let ty = ty.clone();
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: #ty = #export_arg_ident.try_into().unwrap();
                    });
                },
                ExportType::StrRef => {
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: String = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident: &str = &#export_arg_ident;
                    });
                },
                ExportType::Slice( ref ty ) => {
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: Vec< #ty > = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident: &[#ty] = &#export_arg_ident;
                    });
                },
                ExportType::UnknownRef( ref ty ) => {
                    let ty = ty.clone();
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: #ty = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident = &#export_arg_ident;
                    });
                },
                _ => {}
            }
        }

        let metadata = ExportMetadata {
            name: format!( "{}", export.ident ),
            args: export_args_metadata,
            result: export_result_metadata
        };

        let json_metadata = serde_json::to_string( &metadata ).unwrap();
        let encoded_metadata = base_x::encode( ENCODING_BASE, json_metadata.as_bytes() );
        let export_ident = syn::Ident::from( format!( "__JS_EXPORT_{}", &encoded_metadata ) );
        let original_ident = export.ident.clone();

        output.push(
            quote! {
                #[doc(hidden)]
                #[no_mangle]
                #[deny(private_no_mangle_fns)]
                #[allow(unused_imports)]
                pub extern fn #export_ident( #(#export_args),* ) -> #export_result {
                    use ::stdweb::unstable::TryInto;
                    #(#export_args_conversions)*
                    let __result = #original_ident( #(#export_args_idents),* );
                    #export_result_conversion
                    return __result;
                }
            }
        );
    }

    quote! { #(#output)* }
}

fn into_export( ident: syn::Ident, decl: &syn::FnDecl ) -> Export {
    assert!( decl.generics.lifetimes().next().is_none(), "Lifetimes are not yet not supported" );
    assert!( decl.generics.type_params().next().is_none(), "Generics are not supported" );
    assert!( decl.generics.where_clause.is_none(), "`where` clauses are not supported" );
    assert!( decl.variadic.is_none(), "Variadic functions are not supported" );

    let return_ty = match &decl.output {
        &syn::ReturnType::Default => ExportType::Unit,
        &syn::ReturnType::Type( _, ref ty ) => match_type( ty )
    };

    let mut args = Vec::new();
    for (index, arg) in decl.inputs.iter().cloned().enumerate() {
        match arg {
            syn::FnArg::SelfRef( .. ) => panic!( "`&self` is not supported" ),
            syn::FnArg::SelfValue( .. ) => panic!( "`self` is not supported" ),
            syn::FnArg::Ignored( ty ) => {
                let ident = syn::Ident::from( format!( "__arg_{}", index ) );
                args.push( ExportArg {
                    ident,
                    ty: match_type( &ty )
                });
            },
            syn::FnArg::Captured( cap ) => {
                match cap.pat {
                    syn::Pat::Wild( _ ) => {
                        let ident = syn::Ident::from( format!( "__arg_{}", index ) );
                        args.push( ExportArg {
                            ident,
                            ty: match_type( &cap.ty )
                        });
                    },
                    syn::Pat::Ident( pat ) => {
                        assert!( pat.by_ref.is_none(), "`ref` bindings are not supported" );
                        assert!( pat.mutability.is_none(), "`mut` bindings are not supported" );
                        assert!( pat.subpat.is_none(), "Subpatterns are not supported" );

                        args.push( ExportArg {
                            ident: pat.ident,
                            ty: match_type( &cap.ty )
                        });
                    },
                    _ => panic!( "Argument patterns are not supported" )
                }
            },
            syn::FnArg::Inferred( _ ) => panic!( "inferred argument types are not supported" )
        }
    }

    Export {
        ident,
        return_ty,
        args
    }
}

#[proc_macro_attribute]
pub fn js_export( _: TokenStream, input: TokenStream ) -> TokenStream {
    let item: syn::Item = syn::parse( input ).unwrap();
    let mut exports = Vec::new();

    match item {
        syn::Item::Fn( ref function ) => {
            exports.push( into_export( function.ident.clone(), &function.decl ) );
        },
        _ => panic!( "`#[js_export]` attached to an unsupported element!" )
    }

    let generated = process( exports );
    let output = quote! {
        #item
        #generated
    };

    output.into()
}
<commit_msg>Reject extra attributes in `#[js_export]`<commit_after>#![feature(proc_macro)]
#![recursion_limit="128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate base_x;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use proc_macro::TokenStream;

#[derive(Clone, Serialize, Deserialize, Debug)]
enum TypeMetadata {
    I32,
    F64,
    Custom {
        name: Option< String >,
        conversion_fn: String
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
struct ArgMetadata {
    name: String,
    ty: TypeMetadata
}

#[derive(Clone, Serialize, Deserialize, Debug)]
struct ExportMetadata {
    name: String,
    args: Vec< ArgMetadata >,
    result: Option< TypeMetadata >
}

// This is a base62 encoding which consists of only alpha-numeric characters.
// Generated with: (('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a).join("")
const ENCODING_BASE: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

fn match_shallow_path( path: &syn::Path ) -> Option< &str > {
    if path.leading_colon.is_some() || path.segments.len() != 1 {
        return None;
    }

    let segment = &path.segments[ 0 ];
    match &segment.arguments {
        &syn::PathArguments::None => {},
        _ => return None
    }

    Some( segment.ident.as_ref() )
}

fn match_type( ty: &syn::Type ) -> ExportType {
    match ty {
        &syn::Type::Reference( ref ty ) => {
            assert!( ty.mutability.is_none(), "`mut` bindings are not supported" );
            match *ty.elem {
                syn::Type::Path( ref path ) if match_shallow_path( &path.path ).map( |path| path == "str" ).unwrap_or( false ) => {
                    ExportType::StrRef
                },
                syn::Type::Slice( ref slice ) => {
                    ExportType::Slice( (*slice.elem).clone() )
                },
                ref elem => ExportType::UnknownRef( elem.clone() )
            }
        },
        &syn::Type::Path( ref path ) => {
            let name = match match_shallow_path( &path.path ) {
                Some( name ) => name,
                None => return ExportType::Unknown( ty.clone() )
            };

            match name {
                "i32" => ExportType::I32,
                "f64" => ExportType::F64,
                _ => ExportType::Unknown( ty.clone() )
            }
        },
        &syn::Type::Tuple( ref tuple ) if tuple.elems.is_empty() => ExportType::Unit,
        _ => ExportType::Unknown( ty.clone() )
    }
}

enum ExportType {
    Unit,
    I32,
    F64,
    StrRef,
    Slice( syn::Type ),
    Unknown( syn::Type ),
    UnknownRef( syn::Type )
}

struct ExportArg {
    ident: syn::Ident,
    ty: ExportType
}

struct Export {
    ident: syn::Ident,
    return_ty: ExportType,
    args: Vec< ExportArg >
}

fn process( exports: Vec< Export > ) -> quote::Tokens {
    let mut output = Vec::new();
    for export in exports {
        let export_result;
        let export_result_conversion;
        let export_result_metadata;
        let mut export_args = Vec::new();
        let mut export_args_metadata = Vec::new();
        let mut export_args_idents = Vec::new();
        let mut export_args_conversions = Vec::new();

        match export.return_ty {
            ExportType::Unit => {
                export_result = quote! { () };
                export_result_conversion = quote! {};
                export_result_metadata = None;
            },
            ExportType::I32 => {
                export_result = quote! { i32 };
                export_result_conversion = quote! {};
                export_result_metadata = Some( TypeMetadata::I32 );
            },
            ExportType::F64 => {
                export_result = quote! { f64 };
                export_result_conversion = quote! {};
                export_result_metadata = Some( TypeMetadata::F64 );
            },
            ExportType::Unknown( _ ) |
            ExportType::UnknownRef( _ ) |
            ExportType::StrRef |
            ExportType::Slice( _ ) => {
                // TODO: For known types generate more efficient serialization.
                export_result = quote! { () };
                // TODO: Figure out a better way to do this, if possible.
                export_result_conversion = quote! {
                    let __result = ::stdweb::private::IntoNewtype::into_newtype( __result );
                    let __result_memory_required = ::stdweb::private::JsSerializeOwned::memory_required_owned( &__result );
                    let mut __result_arena = ::stdweb::private::PreallocatedArena::new( __result_memory_required );
                    let mut __result = Some( __result );
                    let __result = ::stdweb::private::JsSerializeOwned::into_js_owned( &mut __result, &mut __result_arena );
                    let __result = &__result as *const _;
                    __js_raw_asm!( "Module.STDWEB_PRIVATE.tmp = Module.STDWEB_PRIVATE.to_js( $0 );", __result );
                    let __result = ();
                };
                export_result_metadata = Some( TypeMetadata::Custom {
                    name: None,
                    conversion_fn: "Module.STDWEB_PRIVATE.acquire_tmp".to_owned()
                });
            }
        }

        for arg in &export.args {
            let export_arg_ident = arg.ident.clone();
            let export_arg_ty;
            let export_arg_ty_metadata;
            match arg.ty {
                ExportType::I32 => {
                    export_arg_ty = quote! { i32 };
                    export_arg_ty_metadata = TypeMetadata::I32;
                },
                ExportType::F64 => {
                    export_arg_ty = quote! { f64 };
                    export_arg_ty_metadata = TypeMetadata::F64;
                },
                ExportType::Unit => {
                    panic!( "Receiving arguments of type `()` isn't supported" );
                },
                ExportType::Unknown( _ ) |
                ExportType::UnknownRef( _ ) |
                ExportType::StrRef |
                ExportType::Slice( _ ) => {
                    // TODO: For known types generate more efficient serialization.
                    export_arg_ty = quote! { i32 };
                    export_args_conversions.push( quote! {
                        let #export_arg_ident = {
                            let pointer = #export_arg_ident as *mut ::stdweb::private::SerializedValue;
                            unsafe {
                                let value = (&*pointer).deserialize();
                                ::stdweb::private::__web_free( pointer as *mut u8, ::std::mem::size_of::< ::stdweb::private::SerializedValue >() );
                                value
                            }
                        };
                    });

                    export_arg_ty_metadata = TypeMetadata::Custom {
                        name: None,
                        conversion_fn: "Module.STDWEB_PRIVATE.prepare_any_arg".to_owned()
                    };
                }
            }

            export_args_idents.push( export_arg_ident.clone() );
            export_args_metadata.push( ArgMetadata {
                name: format!( "{}", export_arg_ident ),
                ty: export_arg_ty_metadata
            });
            export_args.push( quote! {
                #export_arg_ident: #export_arg_ty
            });
        }

        for arg in &export.args {
            let export_arg_ident = arg.ident.clone();
            match arg.ty {
                // TODO: Throw a JS exception if `try_into` fails.
                ExportType::Unknown( ref ty ) => {
                    let ty = ty.clone();
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: #ty = #export_arg_ident.try_into().unwrap();
                    });
                },
                ExportType::StrRef => {
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: String = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident: &str = &#export_arg_ident;
                    });
                },
                ExportType::Slice( ref ty ) => {
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: Vec< #ty > = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident: &[#ty] = &#export_arg_ident;
                    });
                },
                ExportType::UnknownRef( ref ty ) => {
                    let ty = ty.clone();
                    export_args_conversions.push( quote! {
                        let #export_arg_ident: #ty = #export_arg_ident.try_into().unwrap();
                        let #export_arg_ident = &#export_arg_ident;
                    });
                },
                _ => {}
            }
        }

        let metadata = ExportMetadata {
            name: format!( "{}", export.ident ),
            args: export_args_metadata,
            result: export_result_metadata
        };

        let json_metadata = serde_json::to_string( &metadata ).unwrap();
        let encoded_metadata = base_x::encode( ENCODING_BASE, json_metadata.as_bytes() );
        let export_ident = syn::Ident::from( format!( "__JS_EXPORT_{}", &encoded_metadata ) );
        let original_ident = export.ident.clone();

        output.push(
            quote! {
                #[doc(hidden)]
                #[no_mangle]
                #[deny(private_no_mangle_fns)]
                #[allow(unused_imports)]
                pub extern fn #export_ident( #(#export_args),* ) -> #export_result {
                    use ::stdweb::unstable::TryInto;
                    #(#export_args_conversions)*
                    let __result = #original_ident( #(#export_args_idents),* );
                    #export_result_conversion
                    return __result;
                }
            }
        );
    }

    quote! { #(#output)* }
}

fn into_export( ident: syn::Ident, decl: &syn::FnDecl ) -> Export {
    assert!( decl.generics.lifetimes().next().is_none(), "Lifetimes are not yet not supported" );
    assert!( decl.generics.type_params().next().is_none(), "Generics are not supported" );
    assert!( decl.generics.where_clause.is_none(), "`where` clauses are not supported" );
    assert!( decl.variadic.is_none(), "Variadic functions are not supported" );

    let return_ty = match &decl.output {
        &syn::ReturnType::Default => ExportType::Unit,
        &syn::ReturnType::Type( _, ref ty ) => match_type( ty )
    };

    let mut args = Vec::new();
    for (index, arg) in decl.inputs.iter().cloned().enumerate() {
        match arg {
            syn::FnArg::SelfRef( .. ) => panic!( "`&self` is not supported" ),
            syn::FnArg::SelfValue( .. ) => panic!( "`self` is not supported" ),
            syn::FnArg::Ignored( ty ) => {
                let ident = syn::Ident::from( format!( "__arg_{}", index ) );
                args.push( ExportArg {
                    ident,
                    ty: match_type( &ty )
                });
            },
            syn::FnArg::Captured( cap ) => {
                match cap.pat {
                    syn::Pat::Wild( _ ) => {
                        let ident = syn::Ident::from( format!( "__arg_{}", index ) );
                        args.push( ExportArg {
                            ident,
                            ty: match_type( &cap.ty )
                        });
                    },
                    syn::Pat::Ident( pat ) => {
                        assert!( pat.by_ref.is_none(), "`ref` bindings are not supported" );
                        assert!( pat.mutability.is_none(), "`mut` bindings are not supported" );
                        assert!( pat.subpat.is_none(), "Subpatterns are not supported" );

                        args.push( ExportArg {
                            ident: pat.ident,
                            ty: match_type( &cap.ty )
                        });
                    },
                    _ => panic!( "Argument patterns are not supported" )
                }
            },
            syn::FnArg::Inferred( _ ) => panic!( "inferred argument types are not supported" )
        }
    }

    Export {
        ident,
        return_ty,
        args
    }
}

#[proc_macro_attribute]
pub fn js_export( attrs: TokenStream, input: TokenStream ) -> TokenStream {
    let item: syn::Item = syn::parse( input ).unwrap();
    let mut exports = Vec::new();

    if !attrs.is_empty() {
        panic!( "Extra attributes are not supported in `#[js_export]`!" );
    }

    match item {
        syn::Item::Fn( ref function ) => {
            exports.push( into_export( function.ident.clone(), &function.decl ) );
        },
        _ => panic!( "`#[js_export]` attached to an unsupported element!" )
    }

    let generated = process( exports );
    let output = quote! {
        #item
        #generated
    };

    output.into()
}
<|endoftext|>


<commit_before>use crate::filesystem;
use crate::walk;

/// Whether or not to show
pub struct FileTypes {
    pub files: bool,
    pub directories: bool,
    pub symlinks: bool,
    pub sockets: bool,
    pub pipes: bool,
    pub executables_only: bool,
    pub empty_only: bool,
}

impl Default for FileTypes {
    fn default() -> FileTypes {
        FileTypes {
            files: false,
            directories: false,
            symlinks: false,
            sockets: false,
            pipes: false,
            executables_only: false,
            empty_only: false,
        }
    }
}

impl FileTypes {
    pub fn should_ignore(&self, entry: &walk::DirEntry) -> bool {
        if let Some(ref entry_type) = entry.file_type() {
            (!self.files && entry_type.is_file())
                || (!self.directories && entry_type.is_dir())
                || (!self.symlinks && entry_type.is_symlink())
                || (!self.sockets && filesystem::is_socket(*entry_type))
                || (!self.pipes && filesystem::is_pipe(*entry_type))
                || (self.executables_only
                    && !entry
                        .metadata()
                        .map(|m| filesystem::is_executable(m))
                        .unwrap_or(false))
                || (self.empty_only && !filesystem::is_empty(entry))
                || !(entry_type.is_file()
                    || entry_type.is_dir()
                    || entry_type.is_symlink()
                    || filesystem::is_socket(*entry_type)
                    || filesystem::is_pipe(*entry_type))
        } else {
            true
        }
    }
}
<commit_msg>A couple of minor recommendations from the Code Quality action (#903)<commit_after>use crate::filesystem;
use crate::walk;

/// Whether or not to show
#[derive(Default)]
pub struct FileTypes {
    pub files: bool,
    pub directories: bool,
    pub symlinks: bool,
    pub sockets: bool,
    pub pipes: bool,
    pub executables_only: bool,
    pub empty_only: bool,
}

impl FileTypes {
    pub fn should_ignore(&self, entry: &walk::DirEntry) -> bool {
        if let Some(ref entry_type) = entry.file_type() {
            (!self.files && entry_type.is_file())
                || (!self.directories && entry_type.is_dir())
                || (!self.symlinks && entry_type.is_symlink())
                || (!self.sockets && filesystem::is_socket(*entry_type))
                || (!self.pipes && filesystem::is_pipe(*entry_type))
                || (self.executables_only
                    && !entry
                        .metadata()
                        .map(filesystem::is_executable)
                        .unwrap_or(false))
                || (self.empty_only && !filesystem::is_empty(entry))
                || !(entry_type.is_file()
                    || entry_type.is_dir()
                    || entry_type.is_symlink()
                    || filesystem::is_socket(*entry_type)
                    || filesystem::is_pipe(*entry_type))
        } else {
            true
        }
    }
}
<|endoftext|>