<commit_before>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use graphics::{
    Context,
    RelativeTransform2d,
    View,
};
use {
    GameWindow,
    GlData,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// OpenGL back-end for Rust-Graphics.
    pub gl_data: &'a mut GlData,
    /// The current context.
    pub context: Context<'a>,
}

/// Update argument.
pub struct UpdateArgs<'a> {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
pub struct KeyPressArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
pub struct KeyReleaseArgs<'a> {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
pub struct MousePressArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs<'a> {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
pub struct MouseMoveArgs<'a> {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs<'a> {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs<'a>),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs<'a>),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs<'a>),
    /// Pressed a mouse button.
    MousePress(MousePressArgs<'a>),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs<'a>),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs<'a>),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs<'a>),
}

enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    PrepareUpdateLoopState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// A game loop iterator.
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    state: GameIteratorState,
    gl_data: GlData,
    context: Context<'a>,
    bg_color: [f32, ..4],
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    next_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W) -> GameIterator<'a, W> {
        let bg_color = game_window.get_settings().background_color;
        let updates_per_second: u64 = 120;
        let max_frames_per_second: u64 = 60;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            gl_data: GlData::new(),
            context: Context::new(),
            last_update: start,
            update_time_in_ns: billion / updates_per_second,
            dt: 1.0 / updates_per_second as f64,
            // You can make this lower if needed.
            min_updates_per_frame: updates_per_second / max_frames_per_second,
            min_ns_per_frame: billion / max_frames_per_second,
            start_render: start,
            next_render: start,
            bg_color: bg_color,
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        match self.state {
            RenderState => {
                if self.game_window.should_close() { return None; }

                self.start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    let r = self.bg_color[0];
                    let g = self.bg_color[1];
                    let b = self.bg_color[2];
                    let a = self.bg_color[3];
                    gl::ClearColor(r, g, b, a);
                    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    return Some(Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            // 'start_render' is always bigger than 'last_update'.
                            ext_dt: (self.start_render - self.last_update) as f64 / billion as f64,
                            gl_data: &mut self.gl_data,
                            context: self.context
                                .trans(-1.0, 1.0)
                                .scale(2.0 / w as f64, -2.0 / h as f64)
                                .store_view().clone()
                        }
                    ));
                }

                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            PrepareUpdateLoopState => {
                self.updated = 0;
                self.next_render = self.start_render + self.min_ns_per_frame;
                self.state = UpdateLoopState;
                return self.next();
            },
            UpdateLoopState => {
                let got_min_updates = self.updated < self.min_updates_per_frame;
                let got_time_to_update = time::precise_time_ns() < self.next_render;
                let before_next_frame = self.last_update + self.update_time_in_ns < self.next_render;

                if ( got_time_to_update || got_min_updates ) && before_next_frame {
                    self.state = HandleEventsState;
                    return self.next();
                }

                // Wait if possible.
                // Convert to ms because that is what the sleep function takes.
                let t = (self.next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            HandleEventsState => {
                // Handle all events before updating.
                return match self.game_window.poll_event() {
                    event::KeyPressed(key) => {
                        Some(KeyPress(KeyPressArgs {
                            key: key,
                        }))
                    },
                    event::KeyReleased(key) => {
                        Some(KeyRelease(KeyReleaseArgs {
                            key: key,
                        }))
                    },
                    event::MouseButtonPressed(mouse_button) => {
                        Some(MousePress(MousePressArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseButtonReleased(mouse_button) => {
                        Some(MouseRelease(MouseReleaseArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseMoved(x, y, relative_move) => {
                        match relative_move {
                            Some((dx, dy)) =>
                                self.state = MouseRelativeMoveState(dx, dy),
                            None => {},
                        };
                        Some(MouseMove(MouseMoveArgs {
                            x: x,
                            y: y,
                        }))
                    },
                    event::NoEvent => {
                        self.state = UpdateState;
                        self.next()
                    },
                }
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = UpdateLoopState;
                self.last_update += self.update_time_in_ns;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<commit_msg>Removed unnecessary lifetimes<commit_after>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use graphics::{
    Context,
    RelativeTransform2d,
    View,
};
use {
    GameWindow,
    GlData,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// OpenGL back-end for Rust-Graphics.
    pub gl_data: &'a mut GlData,
    /// The current context.
    pub context: Context<'a>,
}

/// Update argument.
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
pub struct MouseMoveArgs {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
}

enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    PrepareUpdateLoopState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// A game loop iterator.
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    state: GameIteratorState,
    gl_data: GlData,
    context: Context<'a>,
    bg_color: [f32, ..4],
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    next_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W) -> GameIterator<'a, W> {
        let bg_color = game_window.get_settings().background_color;
        let updates_per_second: u64 = 120;
        let max_frames_per_second: u64 = 60;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            gl_data: GlData::new(),
            context: Context::new(),
            last_update: start,
            update_time_in_ns: billion / updates_per_second,
            dt: 1.0 / updates_per_second as f64,
            // You can make this lower if needed.
            min_updates_per_frame: updates_per_second / max_frames_per_second,
            min_ns_per_frame: billion / max_frames_per_second,
            start_render: start,
            next_render: start,
            bg_color: bg_color,
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        match self.state {
            RenderState => {
                if self.game_window.should_close() { return None; }

                self.start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    let r = self.bg_color[0];
                    let g = self.bg_color[1];
                    let b = self.bg_color[2];
                    let a = self.bg_color[3];
                    gl::ClearColor(r, g, b, a);
                    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    return Some(Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            // 'start_render' is always bigger than 'last_update'.
                            ext_dt: (self.start_render - self.last_update) as f64 / billion as f64,
                            gl_data: &mut self.gl_data,
                            context: self.context
                                .trans(-1.0, 1.0)
                                .scale(2.0 / w as f64, -2.0 / h as f64)
                                .store_view().clone()
                        }
                    ));
                }

                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            PrepareUpdateLoopState => {
                self.updated = 0;
                self.next_render = self.start_render + self.min_ns_per_frame;
                self.state = UpdateLoopState;
                return self.next();
            },
            UpdateLoopState => {
                let got_min_updates = self.updated < self.min_updates_per_frame;
                let got_time_to_update = time::precise_time_ns() < self.next_render;
                let before_next_frame = self.last_update + self.update_time_in_ns < self.next_render;

                if ( got_time_to_update || got_min_updates ) && before_next_frame {
                    self.state = HandleEventsState;
                    return self.next();
                }

                // Wait if possible.
                // Convert to ms because that is what the sleep function takes.
                let t = (self.next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            HandleEventsState => {
                // Handle all events before updating.
                return match self.game_window.poll_event() {
                    event::KeyPressed(key) => {
                        Some(KeyPress(KeyPressArgs {
                            key: key,
                        }))
                    },
                    event::KeyReleased(key) => {
                        Some(KeyRelease(KeyReleaseArgs {
                            key: key,
                        }))
                    },
                    event::MouseButtonPressed(mouse_button) => {
                        Some(MousePress(MousePressArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseButtonReleased(mouse_button) => {
                        Some(MouseRelease(MouseReleaseArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseMoved(x, y, relative_move) => {
                        match relative_move {
                            Some((dx, dy)) =>
                                self.state = MouseRelativeMoveState(dx, dy),
                            None => {},
                        };
                        Some(MouseMove(MouseMoveArgs {
                            x: x,
                            y: y,
                        }))
                    },
                    event::NoEvent => {
                        self.state = UpdateState;
                        self.next()
                    },
                }
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = UpdateLoopState;
                self.last_update += self.update_time_in_ns;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<|endoftext|>


<commit_before>use crate::core::{
    prelude::*,
    util::{geo, validate},
};
use std::collections::HashMap;
use uuid::Uuid;

//TODO: move usecases into separate files

mod confirm_email;
mod create_new_entry;
mod create_new_event;
pub mod create_new_user;
mod delete_event;
mod find_duplicates;
mod login;
mod query_events;
mod rate_entry;
mod search;
#[cfg(test)]
pub mod tests;
mod update_entry;
mod update_event;

pub use self::{
    confirm_email::*, create_new_entry::*, create_new_event::*, create_new_user::*,
    delete_event::*, find_duplicates::*, login::*, query_events::*, rate_entry::*, search::*,
    update_entry::*, update_event::*,
};

// TODO: Remove this function after replacing Bbox with MapBbox
fn map_bbox(bbox: &Bbox) -> Option<geo::MapBbox> {
    let sw = MapPoint::try_from_lat_lng_deg(bbox.south_west.lat, bbox.south_west.lng);
    let ne = MapPoint::try_from_lat_lng_deg(bbox.north_east.lat, bbox.north_east.lng);
    if let (Some(sw), Some(ne)) = (sw, ne) {
        Some(geo::MapBbox::new(sw, ne))
    } else {
        warn!("Invalid Bbox: {:?}", bbox);
        None
    }
}

pub fn get_ratings<D: Db>(db: &D, ids: &[String]) -> Result<Vec<Rating>> {
    Ok(db
        .all_ratings()?
        .iter()
        .filter(|x| ids.iter().any(|id| *id == x.id))
        .cloned()
        .collect())
}

pub fn get_ratings_by_entry_ids<D: Db>(
    db: &D,
    ids: &[String],
) -> Result<HashMap<String, Vec<Rating>>> {
    let ratings = db.all_ratings()?;
    Ok(ids
        .iter()
        .map(|e_id| {
            (
                e_id.clone(),
                ratings
                    .iter()
                    .filter(|r| r.entry_id == **e_id)
                    .cloned()
                    .collect(),
            )
        })
        .collect())
}

pub fn get_comments_by_rating_ids<D: Db>(
    db: &D,
    ids: &[String],
) -> Result<HashMap<String, Vec<Comment>>> {
    let comments = db.all_comments()?;
    Ok(ids
        .iter()
        .map(|r_id| {
            (
                r_id.clone(),
                comments
                    .iter()
                    .filter_map(|comment| {
                        if comment.rating_id == *r_id {
                            Some(comment)
                        } else {
                            None
                        }
                    })
                    .cloned()
                    .collect(),
            )
        })
        .collect())
}

pub fn get_entries<D: Db>(db: &D, ids: &[String]) -> Result<Vec<Entry>> {
    let entries = match ids.len() {
        0 => vec![],
        1 => vec![db.get_entry(&ids[0])?],
        // TODO: Retrieve multiple entries in batches!!!
        _ => db
            .all_entries()?
            .into_iter()
            .filter(|e| ids.iter().any(|id| *id == e.id))
            .collect(),
    };
    Ok(entries)
}

pub fn get_user<D: Db>(
    db: &mut D,
    logged_in_username: &str,
    requested_username: &str,
) -> Result<(String, String)> {
    let u: User = db.get_user(requested_username)?;
    if logged_in_username != requested_username {
        return Err(Error::Parameter(ParameterError::Forbidden));
    }
    Ok((u.username, u.email))
}

pub fn get_event<D: Db>(db: &D, id: &str) -> Result<Event> {
    let mut e: Event = db.get_event(id)?;
    if let Some(ref username) = e.created_by {
        let u = db.get_user(username)?;
        e.created_by = Some(u.email);
    }
    Ok(e)
}

pub fn delete_user(db: &mut Db, login_id: &str, u_id: &str) -> Result<()> {
    if login_id != u_id {
        return Err(Error::Parameter(ParameterError::Forbidden));
    }
    db.delete_user(login_id)?;
    Ok(())
}

pub fn subscribe_to_bbox(coordinates: &[Coordinate], username: &str, db: &mut Db) -> Result<()> {
    if coordinates.len() != 2 {
        return Err(Error::Parameter(ParameterError::Bbox));
    }
    let bbox = Bbox {
        south_west: coordinates[0].clone(),
        north_east: coordinates[1].clone(),
    };
    validate::bbox(&bbox)?;

    // TODO: support multiple subscriptions in KVM (frontend)
    // In the meanwile we just replace existing subscriptions
    // with a new one.
    unsubscribe_all_bboxes_by_username(db, username)?;

    let id = Uuid::new_v4().to_simple_ref().to_string();
    db.create_bbox_subscription(&BboxSubscription {
        id,
        bbox,
        username: username.into(),
    })?;
    Ok(())
}

pub fn get_bbox_subscriptions(username: &str, db: &Db) -> Result<Vec<BboxSubscription>> {
    Ok(db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| s.username == username)
        .collect())
}

pub fn unsubscribe_all_bboxes_by_username(db: &mut Db, username: &str) -> Result<()> {
    let user_subscriptions: Vec<_> = db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| s.username == username)
        .map(|s| s.id)
        .collect();
    for s_id in user_subscriptions {
        db.delete_bbox_subscription(&s_id)?;
    }
    Ok(())
}

pub fn bbox_subscriptions_by_coordinate(
    db: &mut Db,
    x: &Coordinate,
) -> Result<Vec<BboxSubscription>> {
    Ok(db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| {
            if let Some(bbox) = map_bbox(&s.bbox) {
                let pt = geo::MapPoint::from_lat_lng_deg(x.lat, x.lng);
                bbox.contains_point(&pt)
            } else {
                false
            }
        })
        .collect())
}

pub fn email_addresses_from_subscriptions(
    db: &mut Db,
    subs: &[BboxSubscription],
) -> Result<Vec<String>> {
    let usernames: Vec<_> = subs.iter().map(|s| &s.username).collect();

    let mut addresses: Vec<_> = db
        .all_users()?
        .into_iter()
        .filter(|u| usernames.iter().any(|x| **x == u.username))
        .map(|u| u.email)
        .collect();
    addresses.dedup();
    Ok(addresses)
}

pub fn email_addresses_by_coordinate(db: &mut Db, lat: &f64, lng: &f64) -> Result<Vec<String>> {
    let subs = bbox_subscriptions_by_coordinate(
        db,
        &Coordinate {
            lat: *lat,
            lng: *lng,
        },
    )?;
    let addresses = email_addresses_from_subscriptions(db, &subs)?;
    Ok(addresses)
}

pub fn prepare_tag_list(tags: Vec<String>) -> Vec<String> {
    let mut tags: Vec<_> = tags
        .into_iter()
        .map(|t| t.trim().to_owned())
        .filter(|t| !t.is_empty())
        .map(|t| t.split(" ").map(|x| x.to_owned()).collect::<Vec<_>>())
        .flatten()
        .map(|t| t.replace("#", ""))
        .collect();
    tags.dedup();
    tags
}

pub fn check_for_owned_tags<D: Db>(
    db: &D,
    tags: &[String],
    org: &Option<Organization>,
) -> Result<()> {
    let owned_tags = db.get_all_tags_owned_by_orgs()?;
    for t in tags {
        if owned_tags.iter().any(|id| id == t) {
            match org {
                Some(ref o) => {
                    if !o.owned_tags.iter().any(|x| x == t) {
                        return Err(ParameterError::OwnedTag.into());
                    }
                }
                None => {
                    return Err(ParameterError::OwnedTag.into());
                }
            }
        }
    }
    Ok(())
}
<commit_msg>Optimize fetching of multiple entries<commit_after>use crate::core::{
    prelude::*,
    util::{geo, validate},
};
use std::collections::HashMap;
use uuid::Uuid;

//TODO: move usecases into separate files

mod confirm_email;
mod create_new_entry;
mod create_new_event;
pub mod create_new_user;
mod delete_event;
mod find_duplicates;
mod login;
mod query_events;
mod rate_entry;
mod search;
#[cfg(test)]
pub mod tests;
mod update_entry;
mod update_event;

pub use self::{
    confirm_email::*, create_new_entry::*, create_new_event::*, create_new_user::*,
    delete_event::*, find_duplicates::*, login::*, query_events::*, rate_entry::*, search::*,
    update_entry::*, update_event::*,
};

// TODO: Remove this function after replacing Bbox with MapBbox
fn map_bbox(bbox: &Bbox) -> Option<geo::MapBbox> {
    let sw = MapPoint::try_from_lat_lng_deg(bbox.south_west.lat, bbox.south_west.lng);
    let ne = MapPoint::try_from_lat_lng_deg(bbox.north_east.lat, bbox.north_east.lng);
    if let (Some(sw), Some(ne)) = (sw, ne) {
        Some(geo::MapBbox::new(sw, ne))
    } else {
        warn!("Invalid Bbox: {:?}", bbox);
        None
    }
}

pub fn get_ratings<D: Db>(db: &D, ids: &[String]) -> Result<Vec<Rating>> {
    Ok(db
        .all_ratings()?
        .iter()
        .filter(|x| ids.iter().any(|id| *id == x.id))
        .cloned()
        .collect())
}

pub fn get_ratings_by_entry_ids<D: Db>(
    db: &D,
    ids: &[String],
) -> Result<HashMap<String, Vec<Rating>>> {
    let ratings = db.all_ratings()?;
    Ok(ids
        .iter()
        .map(|e_id| {
            (
                e_id.clone(),
                ratings
                    .iter()
                    .filter(|r| r.entry_id == **e_id)
                    .cloned()
                    .collect(),
            )
        })
        .collect())
}

pub fn get_comments_by_rating_ids<D: Db>(
    db: &D,
    ids: &[String],
) -> Result<HashMap<String, Vec<Comment>>> {
    let comments = db.all_comments()?;
    Ok(ids
        .iter()
        .map(|r_id| {
            (
                r_id.clone(),
                comments
                    .iter()
                    .filter_map(|comment| {
                        if comment.rating_id == *r_id {
                            Some(comment)
                        } else {
                            None
                        }
                    })
                    .cloned()
                    .collect(),
            )
        })
        .collect())
}

// TODO: all_entries() currently is very inefficient
// and should be used seldom!!! This constant should
// disappear once multiple entries can be loaded in
// batches.
// TODO: Tune this constant based on performance tests.
const MAX_COUNT_FOR_SINGLE_ENTRY_LOOKUP: usize = 50;

pub fn get_entries<D: Db>(db: &D, ids: &[String]) -> Result<Vec<Entry>> {
    // TODO: Retrieve multiple entries in batches instead of either all or one-by-one!
    let entries = if ids.len() > MAX_COUNT_FOR_SINGLE_ENTRY_LOOKUP {
        db.all_entries()?
            .into_iter()
            .filter(|e| ids.iter().any(|id| *id == e.id))
            .collect()
    } else {
        let mut entries = Vec::with_capacity(ids.len());
        for id in ids {
            match db.get_entry(id) {
                Ok(entry) => {
                    // Success
                    entries.push(entry);
                }
                Err(RepoError::NotFound) => {
                    // Some of the requested entries might not exist
                    info!("One of multiple entries not found: {}", id);
                }
                Err(err) => {
                    // Abort on any unexpected error
                    Err(err)?;
                }
            }
        }
        entries
    };
    Ok(entries)
}

pub fn get_user<D: Db>(
    db: &mut D,
    logged_in_username: &str,
    requested_username: &str,
) -> Result<(String, String)> {
    let u: User = db.get_user(requested_username)?;
    if logged_in_username != requested_username {
        return Err(Error::Parameter(ParameterError::Forbidden));
    }
    Ok((u.username, u.email))
}

pub fn get_event<D: Db>(db: &D, id: &str) -> Result<Event> {
    let mut e: Event = db.get_event(id)?;
    if let Some(ref username) = e.created_by {
        let u = db.get_user(username)?;
        e.created_by = Some(u.email);
    }
    Ok(e)
}

pub fn delete_user(db: &mut Db, login_id: &str, u_id: &str) -> Result<()> {
    if login_id != u_id {
        return Err(Error::Parameter(ParameterError::Forbidden));
    }
    db.delete_user(login_id)?;
    Ok(())
}

pub fn subscribe_to_bbox(coordinates: &[Coordinate], username: &str, db: &mut Db) -> Result<()> {
    if coordinates.len() != 2 {
        return Err(Error::Parameter(ParameterError::Bbox));
    }
    let bbox = Bbox {
        south_west: coordinates[0].clone(),
        north_east: coordinates[1].clone(),
    };
    validate::bbox(&bbox)?;

    // TODO: support multiple subscriptions in KVM (frontend)
    // In the meanwile we just replace existing subscriptions
    // with a new one.
    unsubscribe_all_bboxes_by_username(db, username)?;

    let id = Uuid::new_v4().to_simple_ref().to_string();
    db.create_bbox_subscription(&BboxSubscription {
        id,
        bbox,
        username: username.into(),
    })?;
    Ok(())
}

pub fn get_bbox_subscriptions(username: &str, db: &Db) -> Result<Vec<BboxSubscription>> {
    Ok(db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| s.username == username)
        .collect())
}

pub fn unsubscribe_all_bboxes_by_username(db: &mut Db, username: &str) -> Result<()> {
    let user_subscriptions: Vec<_> = db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| s.username == username)
        .map(|s| s.id)
        .collect();
    for s_id in user_subscriptions {
        db.delete_bbox_subscription(&s_id)?;
    }
    Ok(())
}

pub fn bbox_subscriptions_by_coordinate(
    db: &mut Db,
    x: &Coordinate,
) -> Result<Vec<BboxSubscription>> {
    Ok(db
        .all_bbox_subscriptions()?
        .into_iter()
        .filter(|s| {
            if let Some(bbox) = map_bbox(&s.bbox) {
                let pt = geo::MapPoint::from_lat_lng_deg(x.lat, x.lng);
                bbox.contains_point(&pt)
            } else {
                false
            }
        })
        .collect())
}

pub fn email_addresses_from_subscriptions(
    db: &mut Db,
    subs: &[BboxSubscription],
) -> Result<Vec<String>> {
    let usernames: Vec<_> = subs.iter().map(|s| &s.username).collect();

    let mut addresses: Vec<_> = db
        .all_users()?
        .into_iter()
        .filter(|u| usernames.iter().any(|x| **x == u.username))
        .map(|u| u.email)
        .collect();
    addresses.dedup();
    Ok(addresses)
}

pub fn email_addresses_by_coordinate(db: &mut Db, lat: &f64, lng: &f64) -> Result<Vec<String>> {
    let subs = bbox_subscriptions_by_coordinate(
        db,
        &Coordinate {
            lat: *lat,
            lng: *lng,
        },
    )?;
    let addresses = email_addresses_from_subscriptions(db, &subs)?;
    Ok(addresses)
}

pub fn prepare_tag_list(tags: Vec<String>) -> Vec<String> {
    let mut tags: Vec<_> = tags
        .into_iter()
        .map(|t| t.trim().to_owned())
        .filter(|t| !t.is_empty())
        .map(|t| t.split(" ").map(|x| x.to_owned()).collect::<Vec<_>>())
        .flatten()
        .map(|t| t.replace("#", ""))
        .collect();
    tags.dedup();
    tags
}

pub fn check_for_owned_tags<D: Db>(
    db: &D,
    tags: &[String],
    org: &Option<Organization>,
) -> Result<()> {
    let owned_tags = db.get_all_tags_owned_by_orgs()?;
    for t in tags {
        if owned_tags.iter().any(|id| id == t) {
            match org {
                Some(ref o) => {
                    if !o.owned_tags.iter().any(|x| x == t) {
                        return Err(ParameterError::OwnedTag.into());
                    }
                }
                None => {
                    return Err(ParameterError::OwnedTag.into());
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::ops::{Add, Mul};
use math::{Vec2};
use node::{Node, Graph};
use tensor::{Tensor};
use std::f64;

fn operation(vec: Vec<Tensor<f64>>) -> Tensor<f64> {
    let z = vec[0];
    let y = vec[1];
    let Vec2(row, col) = z.dim();

    for i in 0..row {
        let mut vec_z = Vec::with_capacity(col);
        let mut vec_y = Vec::with_capacity(col);
        let mut m: f64 = f64::NAN;

        for j in 0..col {
            let k = z.get(Vec2(i, j));
            vec_z.push(k);
            m = f64::max(m, k);
            vec_y.push(y.get(Vec2(i, j)));
        }

        let vec_n: Vec<f64> = vec_z.iter().map(|a| a - m).collect();
        let vec_f: Vec<f64> = vec_n.iter().map(|&a| a.exp()).collect();
        let g = vec_f.iter().fold(0.0, |sum, &a| sum + a);
        let log_g = g.ln();

        let cost = vec_y.iter().zip(vec_n.iter()).fold(0.0, |sum, (&a, &b)| {
            sum + (b - log_g) * -a
        });
    }
    n
}

fn operation_prime<T>(gradient: &Tensor<T>, vec: Vec<&Tensor<T>>) -> Vec<Tensor<T>> where T: Mul<Output=T> + Add<Output=T> + Copy {

}

fn calc_dim(dims: Vec<Vec2>) -> Vec2 {
    let Vec2(x1, y1) = dims[0];
    let Vec2(x2, y2) = dims[1];
    assert_eq!(x1, x2);
    assert_eq!(y1, y2);
    Vec2(1, 1)
}

pub fn softmax_cross_entropy_f64(node_id: &'static str, z: Box<Graph<f64>>, y: Box<Graph<f64>>) -> Node<f64> {
    Node::new(node_id, operation, operation_prime, vec![z, y], calc_dim)
}
<commit_msg>partial softxentropy<commit_after>use std::ops::{Add, Mul};
use math::{Vec2};
use node::{Node, Graph};
use tensor::{Tensor};
use std::f64;

fn operation(vec: Vec<Tensor<f64>>) -> Tensor<f64> {
    let z = vec[0];
    let y = vec[1];
    let Vec2(row, col) = z.dim();

    let Cost = 0.0;

    for i in 0..row {
        let mut vec_z = Vec::with_capacity(col);
        let mut vec_y = Vec::with_capacity(col);
        let mut m: f64 = f64::NAN;

        for j in 0..col {
            let k = z.get(Vec2(i, j));
            vec_z.push(k);
            m = f64::max(m, k);
            vec_y.push(y.get(Vec2(i, j)));
        }

        let vec_n: Vec<f64> = vec_z.iter().map(|a| a - m).collect();
        let vec_f: Vec<f64> = vec_n.iter().map(|&a| a.exp()).collect();
        let g = vec_f.iter().fold(0.0, |sum, &a| sum + a);
        let log_g = g.ln();

        let cost = vec_y.iter().zip(vec_n.iter()).fold(0.0, |sum, (&a, &b)| {
            sum + (b - log_g) * -a
        });

        Cost += cost;
    }

}

fn operation_prime<T>(gradient: &Tensor<T>, vec: Vec<&Tensor<T>>) -> Vec<Tensor<T>> where T: Mul<Output=T> + Add<Output=T> + Copy {

}

fn calc_dim(dims: Vec<Vec2>) -> Vec2 {
    let Vec2(x1, y1) = dims[0];
    let Vec2(x2, y2) = dims[1];
    assert_eq!(x1, x2);
    assert_eq!(y1, y2);
    Vec2(1, 1)
}

pub fn softmax_cross_entropy_f64(node_id: &'static str, z: Box<Graph<f64>>, y: Box<Graph<f64>>) -> Node<f64> {
    Node::new(node_id, operation, operation_prime, vec![z, y], calc_dim)
}
<|endoftext|>


<commit_before><commit_msg>Make insert_annotation display warnings instead of printlning<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed config doc demo<commit_after><|endoftext|>


<commit_before><commit_msg>Use more typical defaults for `Projection`.<commit_after><|endoftext|>


<commit_before>// Copyright 2020 Tyler Neely, Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(clippy::all)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

// Ensure the libraries are linked in, despite it not being used directly
#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "zlib")]
extern crate libz_sys;
#[cfg(feature = "zstd")]
extern crate zstd_sys;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(feature = "bzip2")]
#[no_mangle]
pub fn bz_internal_error(errcode: libc::c_int) {
    panic!("bz internal error: {}", errcode);
}
<commit_msg>fix: 'bz_internal_error': symbol multiply defined! (#628)<commit_after>// Copyright 2020 Tyler Neely, Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(clippy::all)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

// Ensure the libraries are linked in, despite it not being used directly
#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "zlib")]
extern crate libz_sys;
#[cfg(feature = "zstd")]
extern crate zstd_sys;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<|endoftext|>


<commit_before>use super::super::log_level::LogLevelCommand;
use types::log_level_type::LogLevelType;

pub fn log_level(level: LogLevelType) -> LogLevelCommand {
    LogLevelCommand::new(level)
}

#[cfg(test)]
mod test {
    use super::*;
    use log_level::LogLevelCommand;
    use types::log_level_type::LogLevelType;

    #[test]
    fn test_log_level() {
        let syntax = log_level(LogLevelType::Warn);
        let actual = LogLevelCommand::new(LogLevelType::Warn);
        assert_eq!(syntax, actual);
    }
}
<commit_msg>log_level_dsl: Remove `super::super`<commit_after>use log_level::LogLevelCommand;
use types::log_level_type::LogLevelType;

pub fn log_level(level: LogLevelType) -> LogLevelCommand {
    LogLevelCommand::new(level)
}

#[cfg(test)]
mod test {
    use super::*;
    use log_level::LogLevelCommand;
    use types::log_level_type::LogLevelType;

    #[test]
    fn test_log_level() {
        let syntax = log_level(LogLevelType::Warn);
        let actual = LogLevelCommand::new(LogLevelType::Warn);
        assert_eq!(syntax, actual);
    }
}
<|endoftext|>


<commit_before>use std::borrow;
use std::error;
use std::fmt;
use std::result;

use super::ClonableError;
use super::BoxedError;
use super::Trace;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

impl<T, E> ResultLiquidChainExt<T> for result::Result<T, E>
where
    E: error::Error + Send + Sync + 'static,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

/// Add context to a `liquid_error::Error`.
pub trait ResultLiquidExt<T> {
    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>;

    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String;

    /// Add state the current stack frame.
    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>;

    /// Add state the current stack frame.
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.trace(trace))
    }

    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error` small to avoid bloating the size of `Result<T>` in the
// success case.  There are already enough memory allocations below, one more shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ClonableError>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T>(self, trace: T) -> Self
    where
        T: Into<borrow::Cow<'static, str>>,
    {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: borrow::Cow<'static, str>) -> Self {
        let trace = Trace::new(trace);
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from the `trace` evaluate to.
    pub fn context<K, V>(self, key: K, value: V) -> Self
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.context_cow_string(key.into(), value.into())
    }

    fn context_cow_string(
        mut self,
        key: borrow::Cow<'static, str>,
        value: borrow::Cow<'static, str>,
    ) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + Send + Sync + 'static>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: BoxedError) -> Self {
        let cause = Some(ClonableError::new(cause));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        self.inner.cause.as_ref().and_then(|e| e.cause())
    }
}
<commit_msg>chore: Clarify internal documentation<commit_after>use std::borrow;
use std::error;
use std::fmt;
use std::result;

use super::ClonableError;
use super::BoxedError;
use super::Trace;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

impl<T, E> ResultLiquidChainExt<T> for result::Result<T, E>
where
    E: error::Error + Send + Sync + 'static,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

/// Add context to a `liquid_error::Error`.
pub trait ResultLiquidExt<T> {
    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>;

    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String;

    /// Add state the current stack frame.
    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>;

    /// Add state the current stack frame.
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.trace(trace))
    }

    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error`'s memory size small to avoid bloating the size of
// `Result<T>` in the success case and spilling over from register-based returns to stack-based
// returns.  There are already enough memory allocations below, one more
// shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ClonableError>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T>(self, trace: T) -> Self
    where
        T: Into<borrow::Cow<'static, str>>,
    {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: borrow::Cow<'static, str>) -> Self {
        let trace = Trace::new(trace);
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from the `trace` evaluate to.
    pub fn context<K, V>(self, key: K, value: V) -> Self
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.context_cow_string(key.into(), value.into())
    }

    fn context_cow_string(
        mut self,
        key: borrow::Cow<'static, str>,
        value: borrow::Cow<'static, str>,
    ) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + Send + Sync + 'static>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: BoxedError) -> Self {
        let cause = Some(ClonableError::new(cause));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        self.inner.cause.as_ref().and_then(|e| e.cause())
    }
}
<|endoftext|>


<commit_before>#![cfg(not(feature="safe"))]

#[no_mangle]
use core;
use core::slice;
use brotli_decompressor::ffi::alloc_util::SubclassableAllocator;
use brotli_decompressor::ffi::interface::{brotli_alloc_func, brotli_free_func, CAllocator, c_void};
use super::alloc_util::BrotliSubclassableAllocator;
use ::enc;
use ::enc::backward_references::BrotliEncoderParams;
use ::enc::encode::{BrotliEncoderParameter, set_parameter};
use ::enc::threading::{SendAlloc,Owned};
use alloc::SliceWrapper;
pub const MAX_THREADS: usize = 16;

struct SliceRef<'a> (&'a [u8]);
impl<'a> SliceWrapper<u8> for SliceRef<'a> {
    fn slice(&self) -> &[u8] { self.0 }
}

#[no_mangle]
pub unsafe extern fn BrotliEncoderCompressMulti(
  num_params: usize,
  param_keys: *const BrotliEncoderParameter,
  param_values: *const u32,
  input_size: usize,
  input: *const u8,
  encoded_size: *mut usize,
  encoded: *mut u8,
  desired_num_threads: usize,
  alloc_func: brotli_alloc_func,
  free_func: brotli_free_func,
  alloc_opaque_per_thread: *mut*mut c_void,
) -> i32 {
  if desired_num_threads == 0 {
    return 0;
  }
  let null_opaques = [core::ptr::null_mut::<c_void>();MAX_THREADS];
  let param_keys_slice = slice::from_raw_parts(param_keys, num_params);
  let param_values_slice = slice::from_raw_parts(param_values, num_params);
  let alloc_opaque = if alloc_opaque_per_thread.is_null() {
    &null_opaques[..]
  } else {
    slice::from_raw_parts(alloc_opaque_per_thread, desired_num_threads)
  };
  let mut params = BrotliEncoderParams::default();
  for (k,v) in param_keys_slice.iter().zip(param_values_slice.iter()) {
    if set_parameter(&mut params, *k, *v) == 0 {
      return 0;
    }
  }
  let num_threads = core::cmp::min(desired_num_threads, MAX_THREADS);
  let mut alloc_array:[_;MAX_THREADS] = [
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[0],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[1%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[2%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[3%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[4%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[5%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[6%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[7%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[8%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[9%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[10%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[11%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[12%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[13%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[14%desired_num_threads],
        }))),
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:alloc_func,
          free_func:free_func,
          opaque:alloc_opaque[15%desired_num_threads],
        }))),
    ];
    let res = enc::compress_multi(
        &params,
        &mut Owned::new(SliceRef(slice::from_raw_parts(input, input_size))),
        slice::from_raw_parts_mut(encoded, *encoded_size),
        &mut alloc_array[..num_threads],
    );
    match res {
      Ok(size) => {
        *encoded_size = size;
        return 1;
      },
      Err(_err) => {
        return 0;
      }
    }
}
<commit_msg>added ffi version to allow worker pools<commit_after>#![cfg(not(feature="safe"))]

#[no_mangle]
use core;
use core::slice;
#[allow(unused_imports)]
use brotli_decompressor;
use brotli_decompressor::ffi::alloc_util::SubclassableAllocator;
use brotli_decompressor::ffi::interface::{brotli_alloc_func, brotli_free_func, CAllocator, c_void};
use super::alloc_util::BrotliSubclassableAllocator;
use ::enc;
use ::enc::backward_references::BrotliEncoderParams;
use ::enc::encode::{BrotliEncoderParameter, set_parameter};
use ::enc::threading::{SendAlloc,Owned};
use alloc::SliceWrapper;
pub const MAX_THREADS: usize = 16;

struct SliceRef<'a> (&'a [u8]);
impl<'a> SliceWrapper<u8> for SliceRef<'a> {
    fn slice(&self) -> &[u8] { self.0 }
}

macro_rules! make_send_alloc {
  ($alloc_func: expr, $free_func: expr, $opaque: expr) => (
    SendAlloc::new(BrotliSubclassableAllocator::new(
      SubclassableAllocator::new(
        CAllocator{
          alloc_func:$alloc_func,
          free_func:$free_func,
          opaque:$opaque,
        })))
  )
}
#[no_mangle]
pub unsafe extern fn BrotliEncoderCompressMulti(
  num_params: usize,
  param_keys: *const BrotliEncoderParameter,
  param_values: *const u32,
  input_size: usize,
  input: *const u8,
  encoded_size: *mut usize,
  encoded: *mut u8,
  desired_num_threads: usize,
  alloc_func: brotli_alloc_func,
  free_func: brotli_free_func,
  alloc_opaque_per_thread: *mut*mut c_void,
) -> i32 {
  if desired_num_threads == 0 {
    return 0;
  }
  let null_opaques = [core::ptr::null_mut::<c_void>();MAX_THREADS];
  let alloc_opaque = if alloc_opaque_per_thread.is_null() {
    &null_opaques[..]
  } else {
    slice::from_raw_parts(alloc_opaque_per_thread, desired_num_threads)
  };
  let param_keys_slice = slice::from_raw_parts(param_keys, num_params);
  let param_values_slice = slice::from_raw_parts(param_values, num_params);
  let mut params = BrotliEncoderParams::default();
  for (k,v) in param_keys_slice.iter().zip(param_values_slice.iter()) {
    if set_parameter(&mut params, *k, *v) == 0 {
      return 0;
    }
  }
  let num_threads = core::cmp::min(desired_num_threads, MAX_THREADS);
  let mut alloc_array:[_;MAX_THREADS] = [
      make_send_alloc!(alloc_func, free_func, alloc_opaque[0]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[1%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[2%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[3%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[4%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[5%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[6%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[7%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[8%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[9%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[10%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[11%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[12%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[13%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[14%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[15%desired_num_threads]),
    ];
    let res = enc::compress_multi(
        &params,
        &mut Owned::new(SliceRef(slice::from_raw_parts(input, input_size))),
        slice::from_raw_parts_mut(encoded, *encoded_size),
        &mut alloc_array[..num_threads],
    );
    match res {
      Ok(size) => {
        *encoded_size = size;
        return 1;
      },
      Err(_err) => {
        return 0;
      }
    }
}

#[no_mangle]
#[repr(C)]
pub struct BrotliEncoderWorkPool {
  custom_allocator: CAllocator,
  work_pool: enc::WorkerPool<enc::CompressionThreadResult<BrotliSubclassableAllocator>,
                             BrotliSubclassableAllocator,
                             (SliceRef<'static>, BrotliEncoderParams)>,
}

#[cfg(feature="no-stdlib")]
fn brotli_new_work_pool_without_custom_alloc(_to_box: BrotliEncoderWorkPool) -> *mut BrotliEncoderWorkPool{
    panic!("Must supply allocators if calling divans when compiled with features=no-stdlib");
}

#[cfg(not(feature="no-stdlib"))]
fn brotli_new_work_pool_without_custom_alloc(to_box: BrotliEncoderWorkPool) -> *mut BrotliEncoderWorkPool{
    brotli_decompressor::ffi::alloc_util::Box::<BrotliEncoderWorkPool>::into_raw(
        brotli_decompressor::ffi::alloc_util::Box::<BrotliEncoderWorkPool>::new(to_box))
}
#[no_mangle]
pub unsafe extern fn BrotliEncoderMakeWorkPool(
  num_threads: usize,
  alloc_func: brotli_alloc_func,
  free_func: brotli_free_func,
  opaque: *mut c_void,
) -> *mut BrotliEncoderWorkPool {
  let allocators = CAllocator {

    alloc_func:alloc_func,
    free_func:free_func,
    opaque:opaque,
  };
  let to_box = BrotliEncoderWorkPool {
    custom_allocator: allocators.clone(),
    work_pool: enc::new_work_pool(core::cmp::min(num_threads, MAX_THREADS)),
  };
  if let Some(alloc) = alloc_func {
    if free_func.is_none() {
      panic!("either both alloc and free must exist or neither");
    }
    let ptr = alloc(allocators.opaque, core::mem::size_of::<BrotliEncoderWorkPool>());
    let brotli_work_pool_ptr = core::mem::transmute::<*mut c_void, *mut BrotliEncoderWorkPool>(ptr);
    core::ptr::write(brotli_work_pool_ptr, to_box);
    brotli_work_pool_ptr
  } else {
    brotli_new_work_pool_without_custom_alloc(to_box)
  }
}
#[cfg(not(feature="no-stdlib"))]
unsafe fn free_work_pool_no_custom_alloc(_work_pool: *mut BrotliEncoderWorkPool) {
    let _state = brotli_decompressor::ffi::alloc_util::Box::from_raw(_work_pool);
}

#[cfg(feature="no-stdlib")]
unsafe fn free_work_pool_no_custom_alloc(_work_pool: *mut BrotliEncoderWorkPool) {
    unreachable!();
}

#[no_mangle]
pub unsafe extern fn BrotliEncoderDestroyWorkPool(work_pool_ptr: *mut BrotliEncoderWorkPool) {
  if let Some(_) = (*work_pool_ptr).custom_allocator.alloc_func {
    if let Some(free_fn) = (*work_pool_ptr).custom_allocator.free_func {
      {
        work_pool_ptr.drop_in_place();
      }
      let _to_free = core::ptr::read(work_pool_ptr);
      let ptr = core::mem::transmute::<*mut BrotliEncoderWorkPool, *mut c_void>(work_pool_ptr);
      free_fn((*work_pool_ptr).custom_allocator.opaque, ptr);
    }
  } else {
    free_work_pool_no_custom_alloc(work_pool_ptr);
  }
}

#[no_mangle]
pub unsafe extern fn BrotliEncoderCompressWorkPool(
  work_pool: *mut BrotliEncoderWorkPool,
  num_params: usize,
  param_keys: *const BrotliEncoderParameter,
  param_values: *const u32,
  input_size: usize,
  input: *const u8,
  encoded_size: *mut usize,
  encoded: *mut u8,
  desired_num_threads: usize,
  alloc_func: brotli_alloc_func,
  free_func: brotli_free_func,
  alloc_opaque_per_thread: *mut*mut c_void,
) -> i32 {
  if desired_num_threads == 0 {
    return 0;
  }
  if work_pool.is_null() {
    return BrotliEncoderCompressMulti(
      num_params,
      param_keys,
      param_values,
      input_size,
      input,
      encoded_size,
      encoded,
      desired_num_threads,
      alloc_func,
      free_func,
      alloc_opaque_per_thread);
  }
  let null_opaques = [core::ptr::null_mut::<c_void>();MAX_THREADS];
  let alloc_opaque = if alloc_opaque_per_thread.is_null() {
    &null_opaques[..]
  } else {
    slice::from_raw_parts(alloc_opaque_per_thread, desired_num_threads)
  };
  let param_keys_slice = slice::from_raw_parts(param_keys, num_params);
  let param_values_slice = slice::from_raw_parts(param_values, num_params);
  let mut params = BrotliEncoderParams::default();
  for (k,v) in param_keys_slice.iter().zip(param_values_slice.iter()) {
    if set_parameter(&mut params, *k, *v) == 0 {
      return 0;
    }
  }
  let num_threads = core::cmp::min(desired_num_threads, MAX_THREADS);
  let mut alloc_array:[_;MAX_THREADS] = [
      make_send_alloc!(alloc_func, free_func, alloc_opaque[0]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[1%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[2%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[3%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[4%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[5%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[6%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[7%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[8%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[9%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[10%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[11%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[12%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[13%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[14%desired_num_threads]),
      make_send_alloc!(alloc_func, free_func, alloc_opaque[15%desired_num_threads]),
    ];
    let res = enc::compress_worker_pool(
      &params,
      &mut Owned::new(SliceRef(slice::from_raw_parts(input, input_size))),
      slice::from_raw_parts_mut(encoded, *encoded_size),
      &mut alloc_array[..num_threads],
      &mut (*work_pool).work_pool,
    );
    match res {
      Ok(size) => {
        *encoded_size = size;
        return 1;
      },
      Err(_err) => {
        return 0;
      }
    }
}
<|endoftext|>


<commit_before>//! A crate for using libcurl as a backend for HTTP git requests with git2-rs.
//!
//! This crate provides one public function, `register`, which will register
//! a custom HTTP transport with libcurl for any HTTP requests made by libgit2.
//! At this time the `register` function is unsafe for the same reasons that
//! `git2::transport::register` is also unsafe.
//!
//! It is not recommended to use this crate wherever possible. The current
//! libcurl backend used, `curl-rust`, only supports executing a request in one
//! method call implying no streaming support. This consequently means that
//! when a repository is cloned the entire contents of the repo are downloaded
//! into memory, and *then* written off to disk by libgit2 afterwards. It
//! should be possible to alleviate this problem in the future.
//!
//! > **NOTE**: At this time this crate likely does not support a `git push`
//! >           operation, only clones.

#![feature(core, io)]
#![doc(html_root_url = "http://alexcrichton.com/git2-rs")]

extern crate git2;
extern crate curl;
extern crate url;
#[macro_use] extern crate log;

use std::io::prelude::*;
use std::io::{self, Cursor};
use std::sync::{Once, ONCE_INIT, Arc, Mutex};

use curl::http::handle::Method;
use curl::http::{Handle, Request};
use git2::Error;
use git2::transport::{SmartSubtransportStream};
use git2::transport::{Transport, SmartSubtransport, Service};
use url::Url;

struct CurlTransport {
    handle: Arc<Mutex<MyHandle>>,
}

struct CurlSubtransport {
    handle: Arc<Mutex<MyHandle>>,
    service: &'static str,
    url_path: &'static str,
    base_url: String,
    method: Method,
    reader: Option<Cursor<Vec<u8>>>,
    sent_request: bool,
}

struct MyHandle(Handle);
unsafe impl Send for MyHandle {} // Handle is not send...

/// Register the libcurl backend for HTTP requests made by libgit2.
///
/// This function takes one parameter, a `handle`, which is used to perform all
/// future HTTP requests. The handle can be previously configured with
/// information such as proxies, SSL information, etc.
///
/// This function is unsafe largely for the same reasons as
/// `git2::transport::register`:
///
/// * The function needs to be synchronized against all other creations of
///   transport (any API calls to libgit2).
/// * The function will leak `handle` as once registered it is not currently
///   possible to unregister the backend.
///
/// This function may be called concurrently, but only the first `handle` will
/// be used. All others will be discarded.
pub unsafe fn register(handle: Handle) {
    static INIT: Once = ONCE_INIT;

    let handle = Arc::new(Mutex::new(MyHandle(handle)));
    let handle2 = handle.clone();
    INIT.call_once(move || {
        git2::transport::register("http", move |remote| {
            factory(remote, handle.clone())
        }).unwrap();
        git2::transport::register("https", move |remote| {
            factory(remote, handle2.clone())
        }).unwrap();
    });
}

fn factory(remote: &git2::Remote, handle: Arc<Mutex<MyHandle>>)
           -> Result<Transport, Error> {
    Transport::smart(remote, true, CurlTransport { handle: handle })
}

impl SmartSubtransport for CurlTransport {
    fn action(&self, url: &str, action: Service)
              -> Result<Box<SmartSubtransportStream>, Error> {
        let (service, path, method) = match action {
            Service::UploadPackLs => {
                ("upload-pack", "/info/refs?service=git-upload-pack", Method::Get)
            }
            Service::UploadPack => {
                ("upload-pack", "/git-upload-pack", Method::Post)
            }
            Service::ReceivePackLs => {
                ("receive-pack", "/info/refs?service=git-receive-pack",
                 Method::Get)
            }
            Service::ReceivePack => {
                ("receive-pack", "/git-receive-pack", Method::Post)
            }
        };
        info!("action {} {}", service, path);
        Ok(Box::new(CurlSubtransport {
            handle: self.handle.clone(),
            service: service,
            url_path: path,
            base_url: url.to_string(),
            method: method,
            reader: None,
            sent_request: false,
        }))
    }

    fn close(&self) -> Result<(), Error> {
        Ok(()) // ...
    }
}

impl CurlSubtransport {
    fn err(&self, desc: &'static str, detail: Option<String>) -> io::Error {
        io::Error::new(io::ErrorKind::Other, desc, detail)
    }

    fn execute(&mut self, mut data: &[u8]) -> io::Result<()> {
        if self.sent_request {
            return Err(self.err("already sent HTTP request", None))
        }
        let agent = format!("git/1.0 (git2-curl {})", env!("CARGO_PKG_VERSION"));

        // Parse our input URL to figure out the host
        let url = format!("{}{}", self.base_url, self.url_path);
        let parsed = try!(Url::parse(&url).map_err(|_| {
            self.err("invalid url, failed to parse", None)
        }));
        let host = try!(parsed.host().ok_or({
            self.err("invalid url, did not have a host", None)
        })).to_string();

        // Prep the request
        debug!("request to {}", url);
        let mut h = self.handle.lock().unwrap();
        let mut req = Request::new(&mut h.0, self.method)
                              .uri(url)
                              .header("User-Agent", &agent)
                              .header("Host", &host)
                              .follow_redirects(true);
        if data.len() > 0 {
            req = req.body(&mut data)
                     .content_length(data.len())
                     .header("Accept", &format!("application/x-git-{}-result",
                                                self.service))
                     .header("Content-Type",
                             &format!("application/x-git-{}-request",
                                      self.service));
        } else {
            req = req.header("Accept", "*/*");
        }

        // Send the request
        let resp = try!(req.exec().map_err(|e| {
            self.err("failed to complete HTTP request", Some(e.to_string()))
        }));
        debug!("response: {}", resp);
        if resp.get_code() != 200 {
            return Err(self.err("failed to receive HTTP 200 response",
                                Some(format!("got {}", resp.get_code()))))
        }

        // Check returned headers
        let expected = match self.method {
            Method::Get => format!("application/x-git-{}-advertisement",
                                   self.service),
            _ => format!("application/x-git-{}-result", self.service),
        };
        if &resp.get_header("content-type") != &[expected.clone()] {
            return Err(self.err("invalid Content-Type header",
                                Some(format!("found `{:?}` expected `{}`",
                                             resp.get_header("Content-Type"),
                                             expected))))
        }

        // Ok, time to read off some data.
        let rdr = Cursor::new(resp.move_body());
        self.reader = Some(rdr);
        Ok(())
    }
}

impl Read for CurlSubtransport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.reader.is_none() {
            try!(self.execute(&[]));
        }
        self.reader.as_mut().unwrap().read(buf)
    }
}

impl Write for CurlSubtransport {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if self.reader.is_none() {
            try!(self.execute(data));
        }
        Ok(data.len())
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
<commit_msg>Remove usage of the `core` feature<commit_after>//! A crate for using libcurl as a backend for HTTP git requests with git2-rs.
//!
//! This crate provides one public function, `register`, which will register
//! a custom HTTP transport with libcurl for any HTTP requests made by libgit2.
//! At this time the `register` function is unsafe for the same reasons that
//! `git2::transport::register` is also unsafe.
//!
//! It is not recommended to use this crate wherever possible. The current
//! libcurl backend used, `curl-rust`, only supports executing a request in one
//! method call implying no streaming support. This consequently means that
//! when a repository is cloned the entire contents of the repo are downloaded
//! into memory, and *then* written off to disk by libgit2 afterwards. It
//! should be possible to alleviate this problem in the future.
//!
//! > **NOTE**: At this time this crate likely does not support a `git push`
//! >           operation, only clones.

#![feature(io)]
#![doc(html_root_url = "http://alexcrichton.com/git2-rs")]

extern crate git2;
extern crate curl;
extern crate url;
#[macro_use] extern crate log;

use std::io::prelude::*;
use std::io::{self, Cursor};
use std::sync::{Once, ONCE_INIT, Arc, Mutex};

use curl::http::handle::Method;
use curl::http::{Handle, Request};
use git2::Error;
use git2::transport::{SmartSubtransportStream};
use git2::transport::{Transport, SmartSubtransport, Service};
use url::Url;

struct CurlTransport {
    handle: Arc<Mutex<MyHandle>>,
}

struct CurlSubtransport {
    handle: Arc<Mutex<MyHandle>>,
    service: &'static str,
    url_path: &'static str,
    base_url: String,
    method: Method,
    reader: Option<Cursor<Vec<u8>>>,
    sent_request: bool,
}

struct MyHandle(Handle);
unsafe impl Send for MyHandle {} // Handle is not send...

/// Register the libcurl backend for HTTP requests made by libgit2.
///
/// This function takes one parameter, a `handle`, which is used to perform all
/// future HTTP requests. The handle can be previously configured with
/// information such as proxies, SSL information, etc.
///
/// This function is unsafe largely for the same reasons as
/// `git2::transport::register`:
///
/// * The function needs to be synchronized against all other creations of
///   transport (any API calls to libgit2).
/// * The function will leak `handle` as once registered it is not currently
///   possible to unregister the backend.
///
/// This function may be called concurrently, but only the first `handle` will
/// be used. All others will be discarded.
pub unsafe fn register(handle: Handle) {
    static INIT: Once = ONCE_INIT;

    let handle = Arc::new(Mutex::new(MyHandle(handle)));
    let handle2 = handle.clone();
    INIT.call_once(move || {
        git2::transport::register("http", move |remote| {
            factory(remote, handle.clone())
        }).unwrap();
        git2::transport::register("https", move |remote| {
            factory(remote, handle2.clone())
        }).unwrap();
    });
}

fn factory(remote: &git2::Remote, handle: Arc<Mutex<MyHandle>>)
           -> Result<Transport, Error> {
    Transport::smart(remote, true, CurlTransport { handle: handle })
}

impl SmartSubtransport for CurlTransport {
    fn action(&self, url: &str, action: Service)
              -> Result<Box<SmartSubtransportStream>, Error> {
        let (service, path, method) = match action {
            Service::UploadPackLs => {
                ("upload-pack", "/info/refs?service=git-upload-pack", Method::Get)
            }
            Service::UploadPack => {
                ("upload-pack", "/git-upload-pack", Method::Post)
            }
            Service::ReceivePackLs => {
                ("receive-pack", "/info/refs?service=git-receive-pack",
                 Method::Get)
            }
            Service::ReceivePack => {
                ("receive-pack", "/git-receive-pack", Method::Post)
            }
        };
        info!("action {} {}", service, path);
        Ok(Box::new(CurlSubtransport {
            handle: self.handle.clone(),
            service: service,
            url_path: path,
            base_url: url.to_string(),
            method: method,
            reader: None,
            sent_request: false,
        }))
    }

    fn close(&self) -> Result<(), Error> {
        Ok(()) // ...
    }
}

impl CurlSubtransport {
    fn err(&self, desc: &'static str, detail: Option<String>) -> io::Error {
        io::Error::new(io::ErrorKind::Other, desc, detail)
    }

    fn execute(&mut self, mut data: &[u8]) -> io::Result<()> {
        if self.sent_request {
            return Err(self.err("already sent HTTP request", None))
        }
        let agent = format!("git/1.0 (git2-curl {})", env!("CARGO_PKG_VERSION"));

        // Parse our input URL to figure out the host
        let url = format!("{}{}", self.base_url, self.url_path);
        let parsed = try!(Url::parse(&url).map_err(|_| {
            self.err("invalid url, failed to parse", None)
        }));
        let host = match parsed.host() {
            Some(host) => host.to_string(),
            None => return Err(self.err("invalid url, did not have a host", None)),
        };

        // Prep the request
        debug!("request to {}", url);
        let mut h = self.handle.lock().unwrap();
        let mut req = Request::new(&mut h.0, self.method)
                              .uri(url)
                              .header("User-Agent", &agent)
                              .header("Host", &host)
                              .follow_redirects(true);
        if data.len() > 0 {
            req = req.body(&mut data)
                     .content_length(data.len())
                     .header("Accept", &format!("application/x-git-{}-result",
                                                self.service))
                     .header("Content-Type",
                             &format!("application/x-git-{}-request",
                                      self.service));
        } else {
            req = req.header("Accept", "*/*");
        }

        // Send the request
        let resp = try!(req.exec().map_err(|e| {
            self.err("failed to complete HTTP request", Some(e.to_string()))
        }));
        debug!("response: {}", resp);
        if resp.get_code() != 200 {
            return Err(self.err("failed to receive HTTP 200 response",
                                Some(format!("got {}", resp.get_code()))))
        }

        // Check returned headers
        let expected = match self.method {
            Method::Get => format!("application/x-git-{}-advertisement",
                                   self.service),
            _ => format!("application/x-git-{}-result", self.service),
        };
        if &resp.get_header("content-type") != &[expected.clone()] {
            return Err(self.err("invalid Content-Type header",
                                Some(format!("found `{:?}` expected `{}`",
                                             resp.get_header("Content-Type"),
                                             expected))))
        }

        // Ok, time to read off some data.
        let rdr = Cursor::new(resp.move_body());
        self.reader = Some(rdr);
        Ok(())
    }
}

impl Read for CurlSubtransport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.reader.is_none() {
            try!(self.execute(&[]));
        }
        self.reader.as_mut().unwrap().read(buf)
    }
}

impl Write for CurlSubtransport {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if self.reader.is_none() {
            try!(self.execute(data));
        }
        Ok(data.len())
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
<|endoftext|>