<commit_before>use std::fmt::Display;
use std::io::Read;
use std::ops::Index;

use crate::common::BitSet;

type Translation = [bool; 512];

struct Field {
    width: usize,
    height: usize,
    infinity: bool,
    finite: BitSet,
}

impl Field {
    pub fn from_input<'a>(input: impl Iterator<Item = &'a [u8]>) -> Self {
        let mut input = input.peekable();

        let width = input.peek().unwrap().len();

        let mut finite = BitSet::new();

        let len = input
            .flatten()
            .enumerate()
            .map(|(index, &c)| {
                if c == b'#' {
                    finite.insert(index);
                }
            })
            .count();

        debug_assert_eq!(len % width, 0);
        let height = len / width;

        Self {
            width,
            height,
            finite,
            infinity: false,
        }
    }

    pub fn advance(&mut self, translation: &[bool; 512]) {
        const INDEX_MASK: usize = (1 << 9) - 1;

        let new_width = self.width + 2;
        let new_height = self.height + 2;

        let mut new_finite = BitSet::with_capacity(new_width * new_height);

        // Now we can just do a normal loop
        for y in 0..new_height {
            for x in 0..new_width {
                let mut mask = if self.infinity { INDEX_MASK } else { 0 };

                for y in y.saturating_sub(2)..=y {
                    if x < 2 {
                        for _ in 0..(2 - x) {
                            mask = self.infinity as usize | (mask << 1);
                        }
                    }

                    for x in x.saturating_sub(2)..=x {
                        mask = (mask << 1) | (self[(x, y)] as usize);
                    }
                }

                if translation[mask & INDEX_MASK] {
                    let index = x + y * new_width;
                    new_finite.insert(index);
                }
            }
        }

        self.width += 2;
        self.height += 2;
        self.finite = new_finite;
        self.infinity = translation[if self.infinity { INDEX_MASK } else { 0 }];
    }

    pub fn len(&self) -> usize {
        assert!(!self.infinity);
        self.finite.len()
    }
}

impl Index<(usize, usize)> for Field {
    type Output = bool;

    #[inline]
    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        if x >= self.width || y >= self.height {
            return &self.infinity;
        }

        let index = x + y * self.width;

        if self.finite.contains(index) {
            &true
        } else {
            &false
        }
    }
}

impl Display for Field {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in 0..self.height {
            for x in 0..self.width {
                if self[(x, y)] {
                    write!(f, "#")?
                } else {
                    write!(f, ".")?
                }
            }
            writeln!(f)?;
        }
        Ok(())
    }
}

fn read_input(input: &mut dyn Read) -> (Translation, Field) {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let mut translation = [false; 512];

    let mut it = buffer.split(|&b| b == b'\n');

    translation
        .iter_mut()
        .zip(it.next().unwrap())
        .for_each(|(t, &c)| *t = c == b'#');

    let field = Field::from_input(it.skip(1));

    (translation, field)
}

fn parts_common(input: &mut dyn Read, count: usize) -> String {
    let (translation, mut field) = read_input(input);

    for _ in 0..count {
        field.advance(&translation);
    }

    field.len().to_string()
}

pub fn part1(input: &mut dyn Read) -> String {
    parts_common(input, 2)
}

pub fn part2(input: &mut dyn Read) -> String {
    parts_common(input, 50)
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/20.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 35);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 3351);
    }
}
<commit_msg>Use running masks instead of computing one by one<commit_after>use std::fmt::Display;
use std::io::Read;
use std::ops::Index;

use crate::common::BitSet;

type Translation = [bool; 512];

struct Field {
    width: usize,
    height: usize,
    infinity: bool,
    finite: BitSet,
}

impl Field {
    pub fn from_input<'a>(input: impl Iterator<Item = &'a [u8]>) -> Self {
        let mut input = input.peekable();

        let width = input.peek().unwrap().len();

        let mut finite = BitSet::new();

        let len = input
            .flatten()
            .enumerate()
            .map(|(index, &c)| {
                if c == b'#' {
                    finite.insert(index);
                }
            })
            .count();

        debug_assert_eq!(len % width, 0);
        let height = len / width;

        Self {
            width,
            height,
            finite,
            infinity: false,
        }
    }

    pub fn advance(&mut self, translation: &[bool; 512]) {
        const INDEX_MASK: usize = (1 << 9) - 1;

        let new_width = self.width + 2;
        let new_height = self.height + 2;

        let mut new_finite = BitSet::with_capacity(new_width * new_height);

        for y in 0..new_height {
            let mut mask = if self.infinity { INDEX_MASK } else { 0 };

            for x in 0..new_width {
                const COLUMN_MASK: usize = 0b001001001;
                let mut submask = if self.infinity { COLUMN_MASK } else { 0 };

                for y in y.saturating_sub(2)..=y {
                    submask = (submask << 3) | (self[(x, y)] as usize);
                }

                mask <<= 1;
                mask &= !COLUMN_MASK;
                mask |= submask;
                mask &= INDEX_MASK;

                if translation[mask] {
                    let index = x + y * new_width;
                    new_finite.insert(index);
                }
            }
        }

        self.width += 2;
        self.height += 2;
        self.finite = new_finite;
        self.infinity = translation[if self.infinity { INDEX_MASK } else { 0 }];
    }

    pub fn len(&self) -> usize {
        assert!(!self.infinity);
        self.finite.len()
    }
}

impl Index<(usize, usize)> for Field {
    type Output = bool;

    #[inline]
    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        if x >= self.width || y >= self.height {
            return &self.infinity;
        }

        let index = x + y * self.width;

        if self.finite.contains(index) {
            &true
        } else {
            &false
        }
    }
}

impl Display for Field {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in 0..self.height {
            for x in 0..self.width {
                if self[(x, y)] {
                    write!(f, "#")?
                } else {
                    write!(f, ".")?
                }
            }
            writeln!(f)?;
        }
        Ok(())
    }
}

fn read_input(input: &mut dyn Read) -> (Translation, Field) {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let mut translation = [false; 512];

    let mut it = buffer.split(|&b| b == b'\n');

    translation
        .iter_mut()
        .zip(it.next().unwrap())
        .for_each(|(t, &c)| *t = c == b'#');

    let field = Field::from_input(it.skip(1));

    (translation, field)
}

fn parts_common(input: &mut dyn Read, count: usize) -> String {
    let (translation, mut field) = read_input(input);

    for _ in 0..count {
        field.advance(&translation);
    }

    field.len().to_string()
}

pub fn part1(input: &mut dyn Read) -> String {
    parts_common(input, 2)
}

pub fn part2(input: &mut dyn Read) -> String {
    parts_common(input, 50)
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/20.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 35);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 3351);
    }
}
<|endoftext|>


<commit_before>use std::pin::{Pin, Unpin};
use std::sync::Arc;
use tab_organizer::ease;
use tab_organizer::state::SortTabs;
use constants::{DRAG_GAP_PX, TOOLBAR_TOTAL_HEIGHT, GROUP_BORDER_WIDTH, GROUP_PADDING_TOP, GROUP_HEADER_HEIGHT, GROUP_PADDING_BOTTOM, TAB_PADDING, TAB_HEIGHT, TAB_BORDER_WIDTH};
use types::{State, DragState, Group, Tab};
use stdweb;
use dominator::animation::{Percentage, MutableAnimationSignal};
use futures::{Future, Poll};
use futures::task::LocalWaker;
use futures_signals::signal::{Signal, SignalExt, MutableSignal, MutableSignalCloned};
use futures_signals::signal_vec::{SignalVec, SignalVecExt, VecDiff};

/*pub(crate) fn delay_animation(animation: &MutableAnimation, visible: &Mutable<bool>) -> impl Future<Item = (), Error = Never> {
    animation.signal().wait_for(Percentage::new(0.0)).select(visible.signal().wait_for(false))
        // TODO a bit gross
        .map(|_| ())
        .map_err(|_| unreachable!())
}*/

fn changed_vec<A, B, C, F>(signal: &mut Option<C>, waker: &LocalWaker, vec: &mut Vec<B>, mut f: F) -> bool
    where C: SignalVec<Item = A> + Unpin,
          F: FnMut(A) -> B {

    let mut changed = false;

    loop {
        match signal.as_mut().map(|signal| signal.poll_vec_change_unpin(waker)) {
            Some(Poll::Ready(Some(change))) => {
                changed = true;

                // TODO move this into futures_signals crate
                match change {
                    VecDiff::Replace { values } => {
                        *vec = values.into_iter().map(|value| f(value)).collect();
                    },
                    VecDiff::InsertAt { index, value } => {
                        vec.insert(index, f(value));
                    },
                    VecDiff::UpdateAt { index, value } => {
                        vec[index] = f(value);
                    },
                    VecDiff::RemoveAt { index } => {
                        vec.remove(index);
                    },
                    VecDiff::Move { old_index, new_index } => {
                        let value = vec.remove(old_index);
                        vec.insert(new_index, value);
                    },
                    VecDiff::Push { value } => {
                        vec.push(f(value));
                    },
                    VecDiff::Pop {} => {
                        vec.pop().unwrap();
                    },
                    VecDiff::Clear {} => {
                        vec.clear();
                    },
                }

                continue;
            },
            Some(Poll::Ready(None)) => {
                *signal = None;
            },
            Some(Poll::Pending) => {},
            None => {},
        }

        return changed;
    }
}

#[inline]
fn changed<A, B>(signal: &mut Option<B>, waker: &LocalWaker) -> bool where B: Signal<Item = A> + Unpin {
    changed_option(signal, waker).is_some()
}

fn changed_option<A, B>(signal: &mut Option<B>, waker: &LocalWaker) -> Option<A> where B: Signal<Item = A> + Unpin {
    let mut changed = None;

    loop {
        match signal.as_mut().map(|signal| signal.poll_change_unpin(waker)) {
            Some(Poll::Ready(Some(value))) => {
                changed = Some(value);
                continue;
            },
            Some(Poll::Ready(None)) => {
                *signal = None;
            },
            Some(Poll::Pending) => {},
            None => {},
        }

        return changed;
    }
}

struct TabState {
    url: Option<MutableSignalCloned<Option<Arc<String>>>>,
    title: Option<MutableSignalCloned<Option<Arc<String>>>>,
    removing: Option<MutableSignal<bool>>,
    dragging: Option<MutableSignal<bool>>,
    insert_animation: Option<MutableAnimationSignal>,
}

impl TabState {
    fn new(tab: Arc<Tab>) -> Self {
        Self {
            url: Some(tab.url.signal_cloned()),
            title: Some(tab.title.signal_cloned()),
            removing: Some(tab.removing.signal()),
            dragging: Some(tab.dragging.signal()),
            insert_animation: Some(tab.insert_animation.signal()),
        }
    }

    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool) {
        let url = changed(&mut self.url, waker);
        let title = changed(&mut self.title, waker);
        let removing = changed(&mut self.removing, waker);
        let dragging = changed(&mut self.dragging, waker);
        let insert_animation = changed(&mut self.insert_animation, waker);
        (
            url || title || removing || dragging || insert_animation,
            url || title
        )
    }
}

struct GroupState<A> {
    signal: Option<A>,
    tabs: Vec<TabState>,
    removing: Option<MutableSignal<bool>>,
    insert_animation: Option<MutableAnimationSignal>,
}

impl<A> GroupState<A> where A: SignalVec<Item = Arc<Tab>> + Unpin {
    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool) {
        let removing = changed(&mut self.removing, waker);
        let insert_animation = changed(&mut self.insert_animation, waker);
        let signal = changed_vec(&mut self.signal, waker, &mut self.tabs, TabState::new);

        let mut tabs = false;
        let mut search = false;

        for mut tab in self.tabs.iter_mut() {
            let x = tab.changed(waker);

            if x.0 {
                tabs = true;
            }

            if x.1 {
                search = true;
            }
        }

        // TODO it should search only when a tab is inserted or updated, not removed
        (
            removing || insert_animation || signal || tabs,
            signal || search
        )
    }
}

struct Waiter<A, B, G, F> where G: FnMut(&Group) -> B {
    signal: Option<A>,
    group_signal: G,
    groups: Vec<GroupState<B>>,
    sort_tabs: Option<MutableSignal<SortTabs>>, // TODO this might be unnecessary
    callback: F,
}

impl<A, B, G, F> Waiter<A, B, G, F>
    where A: SignalVec<Item = Arc<Group>> + Unpin,
          B: SignalVec<Item = Arc<Tab>> + Unpin,
          G: FnMut(&Group) -> B,
          F: FnMut(bool, Option<SortTabs>) {

    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool, Option<SortTabs>) {
        let group_signal = &mut self.group_signal;

        let signal = changed_vec(&mut self.signal, waker, &mut self.groups, |group| {
            GroupState {
                signal: Some(group_signal(&group)),
                tabs: vec![],
                removing: Some(group.removing.signal()),
                insert_animation: Some(group.insert_animation.signal()),
            }
        });

        let mut groups_changed = false;
        let mut groups_searched = false;

        for mut group in self.groups.iter_mut() {
            let (x, y) = group.changed(waker);

            if x {
                groups_changed = true;
            }

            if y {
                groups_searched = true;
            }
        }

        let sort_tabs = changed_option(&mut self.sort_tabs, waker);

        // TODO it should search only when a group is inserted or updated, not removed
        (
            signal || groups_changed || sort_tabs.is_some(),
            signal || groups_searched || sort_tabs.is_some(),
            sort_tabs
        )
    }
}

impl<A, B, G, F> Unpin for Waiter<A, B, G, F> where A: Unpin, B: Unpin, G: FnMut(&Group) -> B {}

impl<A, B, G, F> Future for Waiter<A, B, G, F>
    where A: SignalVec<Item = Arc<Group>> + Unpin,
          B: SignalVec<Item = Arc<Tab>> + Unpin,
          G: FnMut(&Group) -> B,
          F: FnMut(bool, Option<SortTabs>) {

    type Output = ();

    fn poll(mut self: Pin<&mut Self>, waker: &LocalWaker) -> Poll<Self::Output> {
        let (changed, search, sort_tabs) = self.changed(waker);

        if changed {
            let this: &mut Self = &mut *self;
            (this.callback)(search, sort_tabs);
        }

        Poll::Pending
    }
}

pub(crate) fn waiter<F>(state: &State, f: F) -> impl Future<Output = ()> where F: FnMut(bool, Option<SortTabs>) {
    Waiter {
        signal: Some(state.groups.signal_vec_cloned()/*.delay_remove(|group| delay_animation(&group.insert_animation, &group.visible))*/),
        group_signal: |group| group.tabs.signal_vec_cloned()/*.delay_remove(|tab| delay_animation(&tab.insert_animation, &tab.visible))*/,
        groups: vec![],
        sort_tabs: Some(state.options.sort_tabs.signal()),
        callback: f,
    }
}

impl Tab {
	// TODO hacky
    fn height(&self) -> f64 {
        // TODO use range_inclusive ?
        let percentage = ease(self.insert_animation.current_percentage()).into_f64();

        (TAB_BORDER_WIDTH * percentage).round() +
        (TAB_PADDING * percentage).round() +
        (TAB_HEIGHT * percentage).round() +
        (TAB_PADDING * percentage).round() +
        (TAB_BORDER_WIDTH * percentage).round()
    }
}

impl Group {
	// TODO hacky
    // TODO what about when it's dragging ?
    fn height(&self) -> (f64, f64) {
        // TODO use range_inclusive
        let percentage = ease(self.insert_animation.current_percentage()).into_f64();

        (
            (GROUP_BORDER_WIDTH * percentage).round() +
            (GROUP_PADDING_TOP * percentage).round() +
            (if self.show_header { (GROUP_HEADER_HEIGHT * percentage).round() } else { 0.0 }),

            (GROUP_PADDING_BOTTOM * percentage).round()
        )
    }
}

impl State {
	fn hide_tab(&self, tab: &Tab) {
        tab.visible.set_neq(false);
        tab.holding.set_neq(false);
        tab.close_hovered.set_neq(false);
        tab.close_holding.set_neq(false);
        self.unhover_tab(tab);
    }

	// TODO debounce this ?
    // TODO make this simpler somehow ?
    // TODO add in stuff to handle dragging
    pub(crate) fn update(&self, should_search: bool, animate: bool) {
        // TODO add STATE.dragging.state to the waiter
        let dragging = self.dragging.state.lock_ref();
        let search_parser = self.search_parser.lock_ref();

        let top_y = self.scrolling.y.get().round();
        let bottom_y = top_y + (stdweb::web::window().inner_height() as f64 - TOOLBAR_TOTAL_HEIGHT);

        let mut padding: Option<f64> = None;
        let mut current_height: f64 = 0.0;

        self.groups.lock_mut().retain(|group| {
            let mut is_invisible = group.insert_animation.current_percentage() == Percentage::new(0.0);

            if group.removing.get() && is_invisible {
                false

            } else {
                let mut matches_search = false;

                let old_height = current_height;

                let mut tabs_padding: Option<f64> = None;

                let (top_height, bottom_height) = group.height();

                current_height += top_height;

                let tabs_height = current_height;

                // TODO what if there aren't any tabs in the group ?
                group.tabs.lock_mut().retain(|tab| {
                    let mut is_invisible = tab.insert_animation.current_percentage() == Percentage::new(0.0);

                    if tab.removing.get() && is_invisible {
                        false

                    } else {
                        // TODO what about if all the tabs are being dragged ?
                        if should_search && !tab.removing.get() {
                            if search_parser.matches_tab(tab) {
                                matches_search = true;
                                tab.matches_search.set_neq(true);

                                if animate {
                                    tab.insert_animation.animate_to(Percentage::new(1.0));

                                } else {
                                    tab.insert_animation.jump_to(Percentage::new(1.0));
                                }

                            } else {
                                tab.matches_search.set_neq(false);

                                if animate {
                                    tab.insert_animation.animate_to(Percentage::new(0.0));

                                } else {
                                    tab.insert_animation.jump_to(Percentage::new(0.0));
                                    is_invisible = true;
                                }
                            }
                        }

                        if !tab.dragging.get() {
                            let old_height = current_height;

                            current_height += tab.height();

                            if !is_invisible && old_height < bottom_y && current_height > top_y {
                                if let None = tabs_padding {
                                    tabs_padding = Some(old_height);
                                }

                                tab.visible.set_neq(true);

                            } else {
                                self.hide_tab(&tab);
                            }

                        } else {
                            self.hide_tab(&tab);
                        }

                        true
                    }
                });

                if should_search {
                    if matches_search {
                        group.matches_search.set_neq(true);

                        if animate {
                            group.insert_animation.animate_to(Percentage::new(1.0));

                        } else {
                            group.insert_animation.jump_to(Percentage::new(1.0));
                        }

                    } else {
                        group.matches_search.set_neq(false);

                        if animate {
                            group.insert_animation.animate_to(Percentage::new(0.0));

                        } else {
                            group.insert_animation.jump_to(Percentage::new(0.0));
                            is_invisible = true;
                        }
                    }
                }

                let no_tabs_height = current_height;

                current_height += bottom_height;

                if !is_invisible && old_height < bottom_y && current_height > top_y {
                    if let None = padding {
                        padding = Some(old_height);
                    }

                    group.tabs_padding.set_neq(tabs_padding.unwrap_or(no_tabs_height) - tabs_height);
                    group.visible.set_neq(true);

                } else {
                    group.visible.set_neq(false);
                }

                true
            }
        });

        if let Some(DragState::Dragging { .. }) = *dragging {
            // TODO handle this better somehow ?
            current_height += DRAG_GAP_PX;
        }

        self.groups_padding.set_neq(padding.unwrap_or(0.0));
        self.scrolling.height.set_neq(current_height);
    }
}
<commit_msg>Dramatically improving performance of updating<commit_after>use std::pin::{Pin, Unpin};
use std::sync::Arc;
use tab_organizer::ease;
use tab_organizer::state::SortTabs;
use constants::{DRAG_GAP_PX, TOOLBAR_TOTAL_HEIGHT, GROUP_BORDER_WIDTH, GROUP_PADDING_TOP, GROUP_HEADER_HEIGHT, GROUP_PADDING_BOTTOM, TAB_PADDING, TAB_HEIGHT, TAB_BORDER_WIDTH};
use types::{State, DragState, Group, Tab};
use stdweb;
use dominator::animation::{Percentage, MutableAnimationSignal};
use futures::{Future, Poll};
use futures::task::LocalWaker;
use futures_signals::signal::{Signal, SignalExt, MutableSignal, MutableSignalCloned};
use futures_signals::signal_vec::{SignalVec, SignalVecExt, VecDiff};

/*pub(crate) fn delay_animation(animation: &MutableAnimation, visible: &Mutable<bool>) -> impl Future<Item = (), Error = Never> {
    animation.signal().wait_for(Percentage::new(0.0)).select(visible.signal().wait_for(false))
        // TODO a bit gross
        .map(|_| ())
        .map_err(|_| unreachable!())
}*/

fn changed_vec<A, B, C, F>(signal: &mut Option<C>, waker: &LocalWaker, vec: &mut Vec<B>, mut f: F) -> bool
    where C: SignalVec<Item = A> + Unpin,
          F: FnMut(A) -> B {

    let mut changed = false;

    loop {
        match signal.as_mut().map(|signal| signal.poll_vec_change_unpin(waker)) {
            Some(Poll::Ready(Some(change))) => {
                changed = true;

                // TODO move this into futures_signals crate
                match change {
                    VecDiff::Replace { values } => {
                        *vec = values.into_iter().map(|value| f(value)).collect();
                    },
                    VecDiff::InsertAt { index, value } => {
                        vec.insert(index, f(value));
                    },
                    VecDiff::UpdateAt { index, value } => {
                        vec[index] = f(value);
                    },
                    VecDiff::RemoveAt { index } => {
                        vec.remove(index);
                    },
                    VecDiff::Move { old_index, new_index } => {
                        let value = vec.remove(old_index);
                        vec.insert(new_index, value);
                    },
                    VecDiff::Push { value } => {
                        vec.push(f(value));
                    },
                    VecDiff::Pop {} => {
                        vec.pop().unwrap();
                    },
                    VecDiff::Clear {} => {
                        vec.clear();
                    },
                }

                continue;
            },
            Some(Poll::Ready(None)) => {
                *signal = None;
            },
            Some(Poll::Pending) => {},
            None => {},
        }

        return changed;
    }
}

#[inline]
fn changed<A, B>(signal: &mut Option<B>, waker: &LocalWaker) -> bool where B: Signal<Item = A> + Unpin {
    changed_option(signal, waker).is_some()
}

fn changed_option<A, B>(signal: &mut Option<B>, waker: &LocalWaker) -> Option<A> where B: Signal<Item = A> + Unpin {
    let mut changed = None;

    loop {
        match signal.as_mut().map(|signal| signal.poll_change_unpin(waker)) {
            Some(Poll::Ready(Some(value))) => {
                changed = Some(value);
                continue;
            },
            Some(Poll::Ready(None)) => {
                *signal = None;
            },
            Some(Poll::Pending) => {},
            None => {},
        }

        return changed;
    }
}

struct TabState {
    url: Option<MutableSignalCloned<Option<Arc<String>>>>,
    title: Option<MutableSignalCloned<Option<Arc<String>>>>,
    removing: Option<MutableSignal<bool>>,
    dragging: Option<MutableSignal<bool>>,
    insert_animation: Option<MutableAnimationSignal>,
}

impl TabState {
    fn new(tab: Arc<Tab>) -> Self {
        Self {
            url: Some(tab.url.signal_cloned()),
            title: Some(tab.title.signal_cloned()),
            removing: Some(tab.removing.signal()),
            dragging: Some(tab.dragging.signal()),
            insert_animation: Some(tab.insert_animation.signal()),
        }
    }

    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool) {
        let url = changed(&mut self.url, waker);
        let title = changed(&mut self.title, waker);
        let removing = changed(&mut self.removing, waker);
        let dragging = changed(&mut self.dragging, waker);
        let insert_animation = changed(&mut self.insert_animation, waker);
        (
            url || title || removing || dragging || insert_animation,
            url || title
        )
    }
}

struct GroupState<A> {
    signal: Option<A>,
    tabs: Vec<TabState>,
    removing: Option<MutableSignal<bool>>,
    insert_animation: Option<MutableAnimationSignal>,
}

impl<A> GroupState<A> where A: SignalVec<Item = Arc<Tab>> + Unpin {
    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool) {
        let removing = changed(&mut self.removing, waker);
        let insert_animation = changed(&mut self.insert_animation, waker);
        let signal = changed_vec(&mut self.signal, waker, &mut self.tabs, TabState::new);

        let mut tabs = false;
        let mut search = false;

        for mut tab in self.tabs.iter_mut() {
            let x = tab.changed(waker);

            if x.0 {
                tabs = true;
            }

            if x.1 {
                search = true;
            }
        }

        // TODO it should search only when a tab is inserted or updated, not removed
        (
            removing || insert_animation || signal || tabs,
            signal || search
        )
    }
}

struct Waiter<A, B, G, F> where G: FnMut(&Group) -> B {
    signal: Option<A>,
    group_signal: G,
    groups: Vec<GroupState<B>>,
    sort_tabs: Option<MutableSignal<SortTabs>>, // TODO this might be unnecessary
    callback: F,
}

impl<A, B, G, F> Waiter<A, B, G, F>
    where A: SignalVec<Item = Arc<Group>> + Unpin,
          B: SignalVec<Item = Arc<Tab>> + Unpin,
          G: FnMut(&Group) -> B,
          F: FnMut(bool, Option<SortTabs>) {

    fn changed(&mut self, waker: &LocalWaker) -> (bool, bool, Option<SortTabs>) {
        let group_signal = &mut self.group_signal;

        let signal = changed_vec(&mut self.signal, waker, &mut self.groups, |group| {
            GroupState {
                signal: Some(group_signal(&group)),
                tabs: vec![],
                removing: Some(group.removing.signal()),
                insert_animation: Some(group.insert_animation.signal()),
            }
        });

        let mut groups_changed = false;
        let mut groups_searched = false;

        for mut group in self.groups.iter_mut() {
            let (x, y) = group.changed(waker);

            if x {
                groups_changed = true;
            }

            if y {
                groups_searched = true;
            }
        }

        let sort_tabs = changed_option(&mut self.sort_tabs, waker);

        // TODO it should search only when a group is inserted or updated, not removed
        (
            signal || groups_changed || sort_tabs.is_some(),
            signal || groups_searched || sort_tabs.is_some(),
            sort_tabs
        )
    }
}

impl<A, B, G, F> Unpin for Waiter<A, B, G, F> where A: Unpin, B: Unpin, G: FnMut(&Group) -> B {}

impl<A, B, G, F> Future for Waiter<A, B, G, F>
    where A: SignalVec<Item = Arc<Group>> + Unpin,
          B: SignalVec<Item = Arc<Tab>> + Unpin,
          G: FnMut(&Group) -> B,
          F: FnMut(bool, Option<SortTabs>) {

    type Output = ();

    fn poll(mut self: Pin<&mut Self>, waker: &LocalWaker) -> Poll<Self::Output> {
        let (changed, search, sort_tabs) = self.changed(waker);

        if changed {
            let this: &mut Self = &mut *self;
            (this.callback)(search, sort_tabs);
        }

        Poll::Pending
    }
}

pub(crate) fn waiter<F>(state: &State, f: F) -> impl Future<Output = ()> where F: FnMut(bool, Option<SortTabs>) {
    Waiter {
        signal: Some(state.groups.signal_vec_cloned()/*.delay_remove(|group| delay_animation(&group.insert_animation, &group.visible))*/),
        group_signal: |group| group.tabs.signal_vec_cloned()/*.delay_remove(|tab| delay_animation(&tab.insert_animation, &tab.visible))*/,
        groups: vec![],
        sort_tabs: Some(state.options.sort_tabs.signal()),
        callback: f,
    }
}

impl Tab {
	// TODO hacky
    fn height(&self) -> f64 {
        // TODO use range_inclusive ?
        let percentage = ease(self.insert_animation.current_percentage()).into_f64();

        (TAB_BORDER_WIDTH * percentage).round() +
        (TAB_PADDING * percentage).round() +
        (TAB_HEIGHT * percentage).round() +
        (TAB_PADDING * percentage).round() +
        (TAB_BORDER_WIDTH * percentage).round()
    }
}

impl Group {
	// TODO hacky
    // TODO what about when it's dragging ?
    fn height(&self) -> (f64, f64) {
        // TODO use range_inclusive
        let percentage = ease(self.insert_animation.current_percentage()).into_f64();

        (
            (GROUP_BORDER_WIDTH * percentage).round() +
            (GROUP_PADDING_TOP * percentage).round() +
            (if self.show_header { (GROUP_HEADER_HEIGHT * percentage).round() } else { 0.0 }),

            (GROUP_PADDING_BOTTOM * percentage).round()
        )
    }
}

impl State {
	fn hide_tab(&self, tab: &Tab) {
        tab.visible.set_neq(false);
        tab.holding.set_neq(false);
        tab.close_hovered.set_neq(false);
        tab.close_holding.set_neq(false);
        self.unhover_tab(tab);
    }

	// TODO debounce this ?
    // TODO make this simpler somehow ?
    // TODO add in stuff to handle dragging
    pub(crate) fn update(&self, should_search: bool, animate: bool) {
        // TODO add STATE.dragging.state to the waiter
        let dragging = self.dragging.state.lock_ref();
        let search_parser = self.search_parser.lock_ref();

        let top_y = self.scrolling.y.get().round();
        let bottom_y = top_y + (stdweb::web::window().inner_height() as f64 - TOOLBAR_TOTAL_HEIGHT);

        let mut padding: Option<f64> = None;
        let mut current_height: f64 = 0.0;

        self.groups.lock_mut().retain(|group| {
            // TODO remove it when the height is 0 ?
            if group.removing.get() && group.insert_animation.current_percentage() == Percentage::new(0.0) {
                false

            } else {
                let mut matches_search = false;

                let old_height = current_height;

                let mut tabs_padding: Option<f64> = None;

                let (top_height, bottom_height) = group.height();

                current_height += top_height;

                let tabs_height = current_height;

                // TODO what if there aren't any tabs in the group ?
                group.tabs.lock_mut().retain(|tab| {
                    // TODO remove it when the height is 0 ?
                    if tab.removing.get() && tab.insert_animation.current_percentage() == Percentage::new(0.0) {
                        false

                    } else {
                        // TODO what about if all the tabs are being dragged ?
                        if should_search && !tab.removing.get() {
                            if search_parser.matches_tab(tab) {
                                matches_search = true;
                                tab.matches_search.set_neq(true);

                                if animate {
                                    tab.insert_animation.animate_to(Percentage::new(1.0));

                                } else {
                                    tab.insert_animation.jump_to(Percentage::new(1.0));
                                }

                            } else {
                                tab.matches_search.set_neq(false);

                                if animate {
                                    tab.insert_animation.animate_to(Percentage::new(0.0));

                                } else {
                                    tab.insert_animation.jump_to(Percentage::new(0.0));
                                }
                            }
                        }

                        if !tab.dragging.get() {
                            let old_height = current_height;

                            current_height += tab.height();

                            if current_height > old_height && old_height < bottom_y && current_height > top_y {
                                if let None = tabs_padding {
                                    tabs_padding = Some(old_height);
                                }

                                tab.visible.set_neq(true);

                            } else {
                                self.hide_tab(&tab);
                            }

                        } else {
                            self.hide_tab(&tab);
                        }

                        true
                    }
                });

                if should_search {
                    if matches_search {
                        group.matches_search.set_neq(true);

                        if animate {
                            group.insert_animation.animate_to(Percentage::new(1.0));

                        } else {
                            group.insert_animation.jump_to(Percentage::new(1.0));
                        }

                    } else {
                        group.matches_search.set_neq(false);

                        if animate {
                            group.insert_animation.animate_to(Percentage::new(0.0));

                        } else {
                            group.insert_animation.jump_to(Percentage::new(0.0));
                        }
                    }
                }

                let no_tabs_height = current_height;

                current_height += bottom_height;

                // TODO what if the group has height but the tabs don't ?
                // TODO what if the tabs have height but the group doesn't ?
                if current_height > old_height && old_height < bottom_y && current_height > top_y {
                    if let None = padding {
                        padding = Some(old_height);
                    }

                    group.tabs_padding.set_neq(tabs_padding.unwrap_or(no_tabs_height) - tabs_height);
                    group.visible.set_neq(true);

                } else {
                    group.visible.set_neq(false);
                }

                true
            }
        });

        if let Some(DragState::Dragging { .. }) = *dragging {
            // TODO handle this better somehow ?
            current_height += DRAG_GAP_PX;
        }

        self.groups_padding.set_neq(padding.unwrap_or(0.0));
        self.scrolling.height.set_neq(current_height);
    }
}
<|endoftext|>


<commit_before>use crate::core::{Shell, Workspace};
use crate::ops;
use crate::util::config::PathAndArgs;
use crate::util::CargoResult;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

/// Strongly typed options for the `cargo doc` command.
#[derive(Debug)]
pub struct DocOptions {
    /// Whether to attempt to open the browser after compiling the docs
    pub open_result: bool,
    /// Options to pass through to the compiler
    pub compile_opts: ops::CompileOptions,
}

/// Main method for `cargo doc`.
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
    let compilation = ops::compile(ws, &options.compile_opts)?;

    if options.open_result {
        let name = &compilation.root_crate_names[0];
        let kind = options.compile_opts.build_config.single_requested_kind()?;
        let path = compilation.root_output[&kind]
            .with_file_name("doc")
            .join(&name)
            .join("index.html");
        if path.exists() {
            let config_browser = {
                let cfg: Option<PathAndArgs> = ws.config().get("doc.browser")?;
                cfg.map(|path_args| (path_args.path.resolve_program(ws.config()), path_args.args))
            };

            let mut shell = ws.config().shell();
            shell.status("Opening", path.display())?;
            open_docs(&path, &mut shell, config_browser)?;
        }
    }

    Ok(())
}

fn open_docs(
    path: &Path,
    shell: &mut Shell,
    config_browser: Option<(PathBuf, Vec<String>)>,
) -> CargoResult<()> {
    let browser =
        config_browser.or_else(|| Some((PathBuf::from(std::env::var_os("BROWSER")?), Vec::new())));

    match browser {
        Some((browser, initial_args)) => {
            if let Err(e) = Command::new(&browser).args(initial_args).arg(path).status() {
                shell.warn(format!(
                    "Couldn't open docs with {}: {}",
                    browser.to_string_lossy(),
                    e
                ))?;
            }
        }
        None => {
            if let Err(e) = opener::open(&path) {
                let e = e.into();
                crate::display_warning_with_error("couldn't open docs", &e, shell);
            }
        }
    };

    Ok(())
}
<commit_msg>Error when the absence of any crates with files<commit_after>use crate::core::{Shell, Workspace};
use crate::ops;
use crate::util::config::PathAndArgs;
use crate::util::CargoResult;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

/// Strongly typed options for the `cargo doc` command.
#[derive(Debug)]
pub struct DocOptions {
    /// Whether to attempt to open the browser after compiling the docs
    pub open_result: bool,
    /// Options to pass through to the compiler
    pub compile_opts: ops::CompileOptions,
}

/// Main method for `cargo doc`.
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
    let compilation = ops::compile(ws, &options.compile_opts)?;

    if options.open_result {
        let name = &compilation
            .root_crate_names
            .get(0)
            .ok_or_else(|| anyhow::anyhow!("no crates with documentation"))?;
        let kind = options.compile_opts.build_config.single_requested_kind()?;
        let path = compilation.root_output[&kind]
            .with_file_name("doc")
            .join(&name)
            .join("index.html");
        if path.exists() {
            let config_browser = {
                let cfg: Option<PathAndArgs> = ws.config().get("doc.browser")?;
                cfg.map(|path_args| (path_args.path.resolve_program(ws.config()), path_args.args))
            };

            let mut shell = ws.config().shell();
            shell.status("Opening", path.display())?;
            open_docs(&path, &mut shell, config_browser)?;
        }
    }

    Ok(())
}

fn open_docs(
    path: &Path,
    shell: &mut Shell,
    config_browser: Option<(PathBuf, Vec<String>)>,
) -> CargoResult<()> {
    let browser =
        config_browser.or_else(|| Some((PathBuf::from(std::env::var_os("BROWSER")?), Vec::new())));

    match browser {
        Some((browser, initial_args)) => {
            if let Err(e) = Command::new(&browser).args(initial_args).arg(path).status() {
                shell.warn(format!(
                    "Couldn't open docs with {}: {}",
                    browser.to_string_lossy(),
                    e
                ))?;
            }
        }
        None => {
            if let Err(e) = opener::open(&path) {
                let e = e.into();
                crate::display_warning_with_error("couldn't open docs", &e, shell);
            }
        }
    };

    Ok(())
}
<|endoftext|>


<commit_before>#[allow(unused_macros)]
macro_rules! dbg_log {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr, $($arg:tt)*) => {
        println!($fmt, $($arg)*);
    }
}

#[allow(unused_macros)]
macro_rules! console_log {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr, $($arg:tt)*) => {
        println!($fmt, $($arg)*);
    }
}

#[allow(unused_macros)]
macro_rules! dbg_assert {
    ($($arg:tt)*) => {
        debug_assert!($($arg)*);
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! console_log {
    ($fmt:expr) => {
        {
            use ::util::{ console_log_to_js_console };
            console_log_to_js_console($fmt);
        }
    };
    ($fmt:expr, $($arg:tt)*) => {
        {
            use ::util::{ console_log_to_js_console };
            console_log_to_js_console(format!($fmt, $($arg)*));
        }
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! dbg_log {
    ($fmt:expr) => {
        {
            use ::util::{ DEBUG, log_to_js_console };
            if DEBUG { log_to_js_console($fmt); }
        }
    };
    ($fmt:expr, $($arg:tt)*) => {
        {
            use ::util::{ DEBUG, log_to_js_console };
            if DEBUG { log_to_js_console(format!($fmt, $($arg)*)); }
        }
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! dbg_assert {
    ($cond:expr) => {{
        use util::{abort, log_to_js_console, DEBUG};
        if DEBUG && !$cond {
            log_to_js_console(format!(
                "Assertion failed at {}:{}:{}: '{}'",
                file!(),
                line!(),
                column!(),
                stringify!($cond),
            ));
            #[allow(unused_unsafe)]
            unsafe {
                abort();
            }
        }
    }};
    ($cond:expr, $desc:expr) => {{
        use util::{abort, log_to_js_console, DEBUG};
        if DEBUG && !$cond {
            log_to_js_console(format!(
                "Assertion failed at {}:{}:{}: '{}' - '{}'",
                file!(),
                line!(),
                column!(),
                stringify!($cond),
                $desc,
            ));
            #[allow(unused_unsafe)]
            unsafe {
                abort();
            }
        }
    }};
}
<commit_msg>fix rust compiler error: trailing semicolon in macro used in expression position<commit_after>#[allow(unused_macros)]
macro_rules! dbg_log {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr, $($arg:tt)*) => {
        println!($fmt, $($arg)*);
    }
}

#[allow(unused_macros)]
macro_rules! console_log {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr, $($arg:tt)*) => {
        println!($fmt, $($arg)*);
    }
}

#[allow(unused_macros)]
macro_rules! dbg_assert {
    ($($arg:tt)*) => {
        debug_assert!($($arg)*)
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! console_log {
    ($fmt:expr) => {
        {
            use ::util::{ console_log_to_js_console };
            console_log_to_js_console($fmt);
        }
    };
    ($fmt:expr, $($arg:tt)*) => {
        {
            use ::util::{ console_log_to_js_console };
            console_log_to_js_console(format!($fmt, $($arg)*));
        }
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! dbg_log {
    ($fmt:expr) => {
        {
            use ::util::{ DEBUG, log_to_js_console };
            if DEBUG { log_to_js_console($fmt); }
        }
    };
    ($fmt:expr, $($arg:tt)*) => {
        {
            use ::util::{ DEBUG, log_to_js_console };
            if DEBUG { log_to_js_console(format!($fmt, $($arg)*)); }
        }
    };
}

#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! dbg_assert {
    ($cond:expr) => {{
        use util::{abort, log_to_js_console, DEBUG};
        if DEBUG && !$cond {
            log_to_js_console(format!(
                "Assertion failed at {}:{}:{}: '{}'",
                file!(),
                line!(),
                column!(),
                stringify!($cond),
            ));
            #[allow(unused_unsafe)]
            unsafe {
                abort();
            }
        }
    }};
    ($cond:expr, $desc:expr) => {{
        use util::{abort, log_to_js_console, DEBUG};
        if DEBUG && !$cond {
            log_to_js_console(format!(
                "Assertion failed at {}:{}:{}: '{}' - '{}'",
                file!(),
                line!(),
                column!(),
                stringify!($cond),
                $desc,
            ));
            #[allow(unused_unsafe)]
            unsafe {
                abort();
            }
        }
    }};
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.
Copyright 2017 Jihyun Yu. All rights reserved.

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.
*/

use std;
use std::f64::consts::PI;

/// Angle represents a 1D angle. The internal representation is a double precision
/// value in radians, so conversion to and from radians is exact.
/// Conversions between E5, E6, E7, and Degrees are not always
/// exact. For example, Deg(3.1) is different from E6(3100000) or E7(310000000).
///
///     use s2::s1::angle::*;
///     use std::f64::consts::PI;
///
///     // The following conversions between degrees and radians are exact:
///     assert_eq!(Deg(180.), Deg::from(Rad(PI)));
///     for n in 0..9 {
///         // for n == 0..8
///         assert_eq!(Rad(PI/(n as f64)), Deg(180./(n as f64)).into());
///     }
///
///     // These identities hold when the arguments are scaled up or down by any power
///     // of 2. Some similar identities are also true, for example,
///     assert_eq!(Rad(PI/3.), Deg(60.).into());
///
///     // But be aware that this type of identity does not hold in general. For example,
///     assert_ne!(Rad(PI/60.), Deg(3.).into());
///
///     // Similarly, the conversion to radians means that Deg::from(Angle::from(Deg(x)))
///     // does not always equal x. For example,
///
///     // for n == 0..8
///     for n in 0..9 {
///         let x = 45. * (n as f64);
///         assert_eq!(Deg(x), Deg::from(Angle::from(Deg(x))));
///     }
///
///     // but
///     assert_ne!(Deg(60.), Deg::from(Angle::from(Deg(60.))));
///
/// When testing for equality, you should allow for numerical errors (float64Eq)
/// or convert to discrete E5/E6/E7 values first.
#[derive(Clone, Copy, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle(f64);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Rad(pub f64);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Deg(pub f64);

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E5(pub i32);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E6(pub i32);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E7(pub i32);

impl Angle {
    /// rad returns the angle in radians.
    pub fn rad(&self) -> f64 {
        self.0
    }

    /// deg returns the angle in degrees.
    pub fn deg(&self) -> f64 {
        Deg::from(self).0
    }

    /// inf returns an angle larger than any finite angle.
    pub fn inf() -> Self {
        Angle(std::f64::INFINITY)
    }

    /// is_infinite reports whether this Angle is infinite.
    pub fn is_infinite(&self) -> bool {
        self.0.is_infinite()
    }

    /// abs returns the absolute value of the angle.
    pub fn abs(&self) -> Self {
        Angle(self.0.abs())
    }

    /// normalized returns an equivalent angle in [0, 2π).
    pub fn normalized(&self) -> Self {
        let rem = self.0 % (2f64 * PI);
        if rem < 0. {
            Angle(rem + 2f64 * PI)
        } else {
            Angle(rem)
        }
    }
}

impl std::ops::Mul<f64> for Angle {
    type Output = Self;
    fn mul(self, other: f64) -> Self {
        Angle(self.0 * other)
    }
}
impl std::ops::Add<f64> for Angle {
    type Output = Self;
    fn add(self, other: f64) -> Self {
        Angle(self.0 + other)
    }
}

impl std::fmt::Debug for Angle {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:.7}", Deg::from(self).0)
    }
}

macro_rules! convert {
    ($tyname1:ident, $tyname2:ident, $mul:expr) => {
        impl From<$tyname1> for $tyname2 {
            fn from(a: $tyname1) -> Self {
                $tyname2(a.0 * $mul)
            }
        }
        impl<'a> From<&'a $tyname1> for $tyname2 {
            fn from(a: &$tyname1) -> Self {
                $tyname2(a.0 * $mul)
            }
        }
        impl From<$tyname2> for $tyname1 {
            fn from(a: $tyname2) -> Self {
                $tyname1(a.0 / $mul)
            }
        }
        impl<'a> From<&'a $tyname2> for $tyname1 {
            fn from(a: &$tyname2) -> Self {
                $tyname1(a.0 / $mul)
            }
        }
    };
}

macro_rules! convert_i32 {
    ($tyname1:ident, $tyname2:ident, $mul:expr) => {
        impl From<$tyname1> for $tyname2 {
            fn from(a: $tyname1) -> Self {
                $tyname2(f64::from(a.0) * $mul)
            }
        }
        impl<'a> From<&'a $tyname1> for $tyname2 {
            fn from(a: &$tyname1) -> Self {
                $tyname2(f64::from(a.0) * $mul)
            }
        }
        impl From<$tyname2> for $tyname1 {
            fn from(a: $tyname2) -> Self {
                $tyname1((a.0 / $mul).round() as i32)
            }
        }
        impl<'a> From<&'a $tyname2> for $tyname1 {
            fn from(a: &$tyname2) -> Self {
                $tyname1((a.0 / $mul).round() as i32)
            }
        }
    };
}

convert!(Rad, Angle, 1.);
convert!(Deg, Rad, PI / 180.);
convert!(Deg, Angle, PI / 180.);

convert_i32!(E5, Angle, PI / 180. / 1e5);
convert_i32!(E6, Angle, PI / 180. / 1e6);
convert_i32!(E7, Angle, PI / 180. / 1e7);

convert_i32!(E5, Deg, 1. / 1e5);
convert_i32!(E6, Deg, 1. / 1e6);
convert_i32!(E7, Deg, 1. / 1e7);

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

    #[test]
    fn test_deg_rad() {
        let deg = Deg(180.);
        let rad = Angle(PI);
        assert_eq!(rad, deg.clone().into());
        assert_eq!(deg, rad.clone().into());
    }

    #[test]
    fn test_empty_value() {
        assert_eq!(Deg::from(Angle(0.)).0, 0.);
    }

    #[test]
    fn test_pi_radians_exactly_180_degrees() {
        assert_eq!(Angle(PI).rad(), PI);
        assert_eq!(Angle(PI).deg(), 180.);

        assert_eq!(Angle::from(Deg(180.)).rad(), PI);
        assert_eq!(Angle::from(Deg(180.)).deg(), 180.);

        assert_eq!(Angle(PI / 2.).deg(), 90.);

        assert_eq!(Angle(PI / -2.).deg(), -90.);
        assert_eq!(Angle::from(Deg(-45.)).rad(), PI / -4.);
    }

    fn test_rounding(have: f64, want: i32) {
        assert_eq!(E5::from(Deg(have * 1e-5)).0, want);
        assert_eq!(E6::from(Deg(have * 1e-6)).0, want);
        assert_eq!(E7::from(Deg(have * 1e-7)).0, want);
    }

    #[test]
    fn test_e5e6e7_representation() {
        // NOTE(dsymonds): This first test gives a variance in the 16th decimal place. I should track that down.
        assert_f64_eq!(Angle::from(Deg(-45.)).0, Angle::from(E5(-4500000)).0);

        assert_eq!(Angle::from(Deg(-60.)), Angle::from(E6(-60000000)));
        assert_eq!(Angle::from(Deg(-75.)), Angle::from(E7(-750000000)));

        assert_eq!(-17256123, E5::from(Angle::from(Deg(-172.56123))).0);
        assert_eq!(12345678, E6::from(Angle::from(Deg(12.345678))).0);
        assert_eq!(-123456789, E7::from(Angle::from(Deg(-12.3456789))).0);

        test_rounding(0.500000001, 1);
        test_rounding(-0.500000001, -1);
        test_rounding(0.499999999, 0);
        test_rounding(-0.499999999, 0);
    }

    #[test]
    fn test_normalize_correctly_canonicalize_angles() {
        assert_eq!(Angle::from(Deg(0.)), Angle::from(Deg(360.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(-180.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(180.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(540.)).normalized());
        assert_eq!(Angle::from(Deg(90.)), Angle::from(Deg(-270.)).normalized());
    }

    #[test]
    fn test_degrees_vs_radians() {
        // This test tests the exactness of specific values between degrees and radians.
        let mut k = -8.;
        while k <= 8. {
            assert_eq!(Deg(45. * k), Deg::from(Angle(k * PI / 4.)));
            assert_eq!(Angle::from(Deg(45. * k)), Angle(k * PI / 4.));
            k += 1.;
        }

        for k in 0..30 {
            let n = (1i32 << k) as f64;
            assert_eq!(Angle::from(Deg(180. / n)), Angle(PI / (1. * n)));
            assert_eq!(Angle::from(Deg(60. / n)), Angle(PI / (3. * n)));
            assert_eq!(Angle::from(Deg(36. / n)), Angle(PI / (5. * n)));
            assert_eq!(Angle::from(Deg(20. / n)), Angle(PI / (9. * n)));
            assert_eq!(Angle::from(Deg(4. / n)), Angle(PI / (45. * n)));
        }

        // We also spot check a non-identity.
        assert_f64_eq!(Deg::from(Angle::from(Deg(60.))).0, Deg(60.).0);
    }
}

// BUG(dsymonds): The major differences from the C++ version are:
//   - no unsigned E5/E6/E7 methods
//   - no S2Point or S2LatLng constructors
//   - no comparison or arithmetic operators
<commit_msg>Add Angle::max<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.
Copyright 2017 Jihyun Yu. All rights reserved.

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.
*/

use std;
use std::f64::consts::PI;

/// Angle represents a 1D angle. The internal representation is a double precision
/// value in radians, so conversion to and from radians is exact.
/// Conversions between E5, E6, E7, and Degrees are not always
/// exact. For example, Deg(3.1) is different from E6(3100000) or E7(310000000).
///
///     use s2::s1::angle::*;
///     use std::f64::consts::PI;
///
///     // The following conversions between degrees and radians are exact:
///     assert_eq!(Deg(180.), Deg::from(Rad(PI)));
///     for n in 0..9 {
///         // for n == 0..8
///         assert_eq!(Rad(PI/(n as f64)), Deg(180./(n as f64)).into());
///     }
///
///     // These identities hold when the arguments are scaled up or down by any power
///     // of 2. Some similar identities are also true, for example,
///     assert_eq!(Rad(PI/3.), Deg(60.).into());
///
///     // But be aware that this type of identity does not hold in general. For example,
///     assert_ne!(Rad(PI/60.), Deg(3.).into());
///
///     // Similarly, the conversion to radians means that Deg::from(Angle::from(Deg(x)))
///     // does not always equal x. For example,
///
///     // for n == 0..8
///     for n in 0..9 {
///         let x = 45. * (n as f64);
///         assert_eq!(Deg(x), Deg::from(Angle::from(Deg(x))));
///     }
///
///     // but
///     assert_ne!(Deg(60.), Deg::from(Angle::from(Deg(60.))));
///
/// When testing for equality, you should allow for numerical errors (float64Eq)
/// or convert to discrete E5/E6/E7 values first.
#[derive(Clone, Copy, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle(f64);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Rad(pub f64);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Deg(pub f64);

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E5(pub i32);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E6(pub i32);
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct E7(pub i32);

impl Angle {
    /// rad returns the angle in radians.
    pub fn rad(&self) -> f64 {
        self.0
    }

    /// deg returns the angle in degrees.
    pub fn deg(&self) -> f64 {
        Deg::from(self).0
    }

    /// inf returns an angle larger than any finite angle.
    pub fn inf() -> Self {
        Angle(std::f64::INFINITY)
    }

    /// is_infinite reports whether this Angle is infinite.
    pub fn is_infinite(&self) -> bool {
        self.0.is_infinite()
    }

    /// abs returns the absolute value of the angle.
    pub fn abs(&self) -> Self {
        Angle(self.0.abs())
    }

    /// normalized returns an equivalent angle in [0, 2π).
    pub fn normalized(&self) -> Self {
        let rem = self.0 % (2f64 * PI);
        if rem < 0. {
            Angle(rem + 2f64 * PI)
        } else {
            Angle(rem)
        }
    }

    pub fn max(self, other: Angle) -> Self {
        if self.0 < other.0 {
            return other;
        } else {
            return self;
        }
    }
}

impl std::ops::Mul<f64> for Angle {
    type Output = Self;
    fn mul(self, other: f64) -> Self {
        Angle(self.0 * other)
    }
}
impl std::ops::Add<f64> for Angle {
    type Output = Self;
    fn add(self, other: f64) -> Self {
        Angle(self.0 + other)
    }
}

impl std::fmt::Debug for Angle {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:.7}", Deg::from(self).0)
    }
}

macro_rules! convert {
    ($tyname1:ident, $tyname2:ident, $mul:expr) => {
        impl From<$tyname1> for $tyname2 {
            fn from(a: $tyname1) -> Self {
                $tyname2(a.0 * $mul)
            }
        }
        impl<'a> From<&'a $tyname1> for $tyname2 {
            fn from(a: &$tyname1) -> Self {
                $tyname2(a.0 * $mul)
            }
        }
        impl From<$tyname2> for $tyname1 {
            fn from(a: $tyname2) -> Self {
                $tyname1(a.0 / $mul)
            }
        }
        impl<'a> From<&'a $tyname2> for $tyname1 {
            fn from(a: &$tyname2) -> Self {
                $tyname1(a.0 / $mul)
            }
        }
    };
}

macro_rules! convert_i32 {
    ($tyname1:ident, $tyname2:ident, $mul:expr) => {
        impl From<$tyname1> for $tyname2 {
            fn from(a: $tyname1) -> Self {
                $tyname2(f64::from(a.0) * $mul)
            }
        }
        impl<'a> From<&'a $tyname1> for $tyname2 {
            fn from(a: &$tyname1) -> Self {
                $tyname2(f64::from(a.0) * $mul)
            }
        }
        impl From<$tyname2> for $tyname1 {
            fn from(a: $tyname2) -> Self {
                $tyname1((a.0 / $mul).round() as i32)
            }
        }
        impl<'a> From<&'a $tyname2> for $tyname1 {
            fn from(a: &$tyname2) -> Self {
                $tyname1((a.0 / $mul).round() as i32)
            }
        }
    };
}

convert!(Rad, Angle, 1.);
convert!(Deg, Rad, PI / 180.);
convert!(Deg, Angle, PI / 180.);

convert_i32!(E5, Angle, PI / 180. / 1e5);
convert_i32!(E6, Angle, PI / 180. / 1e6);
convert_i32!(E7, Angle, PI / 180. / 1e7);

convert_i32!(E5, Deg, 1. / 1e5);
convert_i32!(E6, Deg, 1. / 1e6);
convert_i32!(E7, Deg, 1. / 1e7);

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

    #[test]
    fn test_deg_rad() {
        let deg = Deg(180.);
        let rad = Angle(PI);
        assert_eq!(rad, deg.clone().into());
        assert_eq!(deg, rad.clone().into());
    }

    #[test]
    fn test_empty_value() {
        assert_eq!(Deg::from(Angle(0.)).0, 0.);
    }

    #[test]
    fn test_pi_radians_exactly_180_degrees() {
        assert_eq!(Angle(PI).rad(), PI);
        assert_eq!(Angle(PI).deg(), 180.);

        assert_eq!(Angle::from(Deg(180.)).rad(), PI);
        assert_eq!(Angle::from(Deg(180.)).deg(), 180.);

        assert_eq!(Angle(PI / 2.).deg(), 90.);

        assert_eq!(Angle(PI / -2.).deg(), -90.);
        assert_eq!(Angle::from(Deg(-45.)).rad(), PI / -4.);
    }

    fn test_rounding(have: f64, want: i32) {
        assert_eq!(E5::from(Deg(have * 1e-5)).0, want);
        assert_eq!(E6::from(Deg(have * 1e-6)).0, want);
        assert_eq!(E7::from(Deg(have * 1e-7)).0, want);
    }

    #[test]
    fn test_e5e6e7_representation() {
        // NOTE(dsymonds): This first test gives a variance in the 16th decimal place. I should track that down.
        assert_f64_eq!(Angle::from(Deg(-45.)).0, Angle::from(E5(-4500000)).0);

        assert_eq!(Angle::from(Deg(-60.)), Angle::from(E6(-60000000)));
        assert_eq!(Angle::from(Deg(-75.)), Angle::from(E7(-750000000)));

        assert_eq!(-17256123, E5::from(Angle::from(Deg(-172.56123))).0);
        assert_eq!(12345678, E6::from(Angle::from(Deg(12.345678))).0);
        assert_eq!(-123456789, E7::from(Angle::from(Deg(-12.3456789))).0);

        test_rounding(0.500000001, 1);
        test_rounding(-0.500000001, -1);
        test_rounding(0.499999999, 0);
        test_rounding(-0.499999999, 0);
    }

    #[test]
    fn test_normalize_correctly_canonicalize_angles() {
        assert_eq!(Angle::from(Deg(0.)), Angle::from(Deg(360.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(-180.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(180.)).normalized());
        assert_eq!(Angle::from(Deg(180.)), Angle::from(Deg(540.)).normalized());
        assert_eq!(Angle::from(Deg(90.)), Angle::from(Deg(-270.)).normalized());
    }

    #[test]
    fn test_degrees_vs_radians() {
        // This test tests the exactness of specific values between degrees and radians.
        let mut k = -8.;
        while k <= 8. {
            assert_eq!(Deg(45. * k), Deg::from(Angle(k * PI / 4.)));
            assert_eq!(Angle::from(Deg(45. * k)), Angle(k * PI / 4.));
            k += 1.;
        }

        for k in 0..30 {
            let n = (1i32 << k) as f64;
            assert_eq!(Angle::from(Deg(180. / n)), Angle(PI / (1. * n)));
            assert_eq!(Angle::from(Deg(60. / n)), Angle(PI / (3. * n)));
            assert_eq!(Angle::from(Deg(36. / n)), Angle(PI / (5. * n)));
            assert_eq!(Angle::from(Deg(20. / n)), Angle(PI / (9. * n)));
            assert_eq!(Angle::from(Deg(4. / n)), Angle(PI / (45. * n)));
        }

        // We also spot check a non-identity.
        assert_f64_eq!(Deg::from(Angle::from(Deg(60.))).0, Deg(60.).0);
    }
}

// BUG(dsymonds): The major differences from the C++ version are:
//   - no unsigned E5/E6/E7 methods
//   - no S2Point or S2LatLng constructors
//   - no comparison or arithmetic operators
<|endoftext|>


<commit_before>use std::io::{Result, Write};
use analysis::functions::Info;
use analysis::special_functions::{Infos, Type};

pub fn generate(w: &mut Write, type_name: &str, functions: &[Info], specials: &Infos, in_trait: bool)
        -> Result<()> {
    for (type_, name) in specials.iter() {
        match *type_ {
            Type::Compare => {
                if specials.get(&Type::Equal).is_none() {
                    try!(generate_eq_compare(w, type_name, lookup(functions, name), in_trait));
                }
                try!(generate_ord(w, type_name, lookup(functions, name), in_trait));
            }
            Type::Equal => {
                try!(generate_eq(w, type_name, lookup(functions, name), in_trait));
            }
            Type::ToString => try!(generate_display(w, type_name, lookup(functions, name), in_trait)),
            _ => {}
        }
    }
    Ok(())
}

fn lookup<'a>(functions: &'a [Info], name: &str) -> &'a Info {
    functions.iter()
        .find(|f| f.glib_name == name)
        .unwrap()
}

fn generate_display(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    use analysis::out_parameters::Mode;

    let call = if in_trait {
        format!("{type_name}Ext::{func_name}(self)",
                type_name = type_name, func_name = func.name)
    } else {
        format!("self.{func_name}()",
                func_name = func.name)
    };

    let body = if let Mode::Throws(_) = func.outs.mode {
        format!("if let Ok(val) = {} {{
            write!(f, \"{{}}\", val)
        }} else {{
            Err(fmt::Error)
        }}", call)
    } else {
        format!("write!(f, \"{{}}\", {})", call)
    };
    writeln!(w, "
impl fmt::Display for {type_name} {{
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{
        {body}
    }}
}}", type_name = type_name, body = body)
}

fn generate_eq(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = if in_trait {
        format!("{type_name}Ext::{func_name}(self, other)",
                type_name = type_name, func_name = func.name)
    } else {
        format!("self.{func_name}(other)",
                func_name = func.name)
    };

    writeln!(w, "
impl PartialEq for {type_name} {{
    #[inline]
    fn eq(&self, other: &Self) -> bool {{
        {call}
    }}
}}

impl Eq for {type_name} {{}}", type_name = type_name, call = call)
}

fn generate_eq_compare(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = if in_trait {
        format!("{type_name}Ext::{func_name}(self, other)",
                type_name = type_name, func_name = func.name)
    } else {
        format!("self.{func_name}(other)",
                func_name = func.name)
    };

    writeln!(w, "
impl PartialEq for {type_name} {{
    #[inline]
    fn eq(&self, other: &Self) -> bool {{
        {call} == 0
    }}
}}

impl Eq for {type_name} {{}}", type_name = type_name, call = call)
}

fn generate_ord(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = if in_trait {
        format!("{type_name}Ext::{func_name}(self, other)",
                type_name = type_name, func_name = func.name)
    } else {
        format!("self.{func_name}(other)",
                func_name = func.name)
    };

    writeln!(w, "
impl PartialOrd for {type_name} {{
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {{
        {call}.partial_cmp(&0)
    }}
}}

impl Ord for {type_name} {{
    #[inline]
    fn cmp(&self, other: &Self) -> cmp::Ordering {{
        {call}.cmp(&0)
    }}
}}", type_name = type_name, call = call)
}
<commit_msg>Generate trait impl function call generically in one place<commit_after>use std::io::{Result, Write};
use analysis::functions::Info;
use analysis::special_functions::{Infos, Type};

pub fn generate(w: &mut Write, type_name: &str, functions: &[Info], specials: &Infos, in_trait: bool)
        -> Result<()> {
    for (type_, name) in specials.iter() {
        match *type_ {
            Type::Compare => {
                if specials.get(&Type::Equal).is_none() {
                    try!(generate_eq_compare(w, type_name, lookup(functions, name), in_trait));
                }
                try!(generate_ord(w, type_name, lookup(functions, name), in_trait));
            }
            Type::Equal => {
                try!(generate_eq(w, type_name, lookup(functions, name), in_trait));
            }
            Type::ToString => try!(generate_display(w, type_name, lookup(functions, name), in_trait)),
            _ => {}
        }
    }
    Ok(())
}

fn lookup<'a>(functions: &'a [Info], name: &str) -> &'a Info {
    functions.iter()
        .find(|f| f.glib_name == name)
        .unwrap()
}

fn generate_call(type_name: &str, func_name: &str, args: &[&str], in_trait: bool) -> String {
    let mut args_string = String::new();

    if in_trait {
        args_string.push_str("self");
    }

    if !args.is_empty() {
        if in_trait {
            args_string.push_str(", ");
        }
        args_string.push_str(&args.join(", "));
    }

    if in_trait {
        format!("{type_name}Ext::{func_name}({args})",
                type_name = type_name, func_name = func_name, args = args_string)
    } else {
        format!("self.{func_name}({args})",
                func_name = func_name, args = args_string)
    }
}

fn generate_display(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    use analysis::out_parameters::Mode;

    let call = generate_call(type_name, &func.name, &[], in_trait);
    let body = if let Mode::Throws(_) = func.outs.mode {
        format!("if let Ok(val) = {} {{
            write!(f, \"{{}}\", val)
        }} else {{
            Err(fmt::Error)
        }}", call)
    } else {
        format!("write!(f, \"{{}}\", {})", call)
    };

    writeln!(w, "
impl fmt::Display for {type_name} {{
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{
        {body}
    }}
}}", type_name = type_name, body = body)
}

fn generate_eq(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = generate_call(type_name, &func.name, &["other"], in_trait);

    writeln!(w, "
impl PartialEq for {type_name} {{
    #[inline]
    fn eq(&self, other: &Self) -> bool {{
        {call}
    }}
}}

impl Eq for {type_name} {{}}", type_name = type_name, call = call)
}

fn generate_eq_compare(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = generate_call(type_name, &func.name, &["other"], in_trait);

    writeln!(w, "
impl PartialEq for {type_name} {{
    #[inline]
    fn eq(&self, other: &Self) -> bool {{
        {call} == 0
    }}
}}

impl Eq for {type_name} {{}}", type_name = type_name, call = call)
}

fn generate_ord(w: &mut Write, type_name: &str, func: &Info, in_trait: bool) -> Result<()> {
    let call = generate_call(type_name, &func.name, &["other"], in_trait);

    writeln!(w, "
impl PartialOrd for {type_name} {{
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {{
        {call}.partial_cmp(&0)
    }}
}}

impl Ord for {type_name} {{
    #[inline]
    fn cmp(&self, other: &Self) -> cmp::Ordering {{
        {call}.cmp(&0)
    }}
}}", type_name = type_name, call = call)
}
<|endoftext|>


<commit_before>use super::{read_query, wrap_query, write_query};
use crate::{
    Document, ReqlResponse, Request, Result,
    Session, SessionManager,
    errors::*,
};

use protobuf::ProtobufEnum;
use ql2::proto::{Query_QueryType as QueryType, Response_ErrorType as ErrorType,
                 Response_ResponseType as ResponseType};
use r2d2::PooledConnection;
use serde::de::DeserializeOwned;
use serde_json::{Value, from_slice, from_value};
use std::error::Error as StdError;
use futures::{Future, Sink};

impl<T: DeserializeOwned + Send + std::fmt::Debug> Request<T> {
    fn conn(&self) -> Result<PooledConnection<SessionManager>> {
        match self.pool.get() {
            Ok(mut conn) => {
                conn.id = conn.id.wrapping_add(1);
                Ok(conn)
            }
            Err(error) => Err(error)?,
        }
    }

    pub fn submit(mut self) {
        let mut conn = match self.conn() {
            Ok(conn) => conn,
            Err(error) => {
                let _ = self.tx.clone().send(Err(error));
                return;
            }
        };
        // Try sending the query
        log::debug!("submiting to server");
        {
            let mut i = 0;
            let mut connect = false;
            let reproducible = self.cfg.opts.reproducible;
            while i < self.cfg.opts.retries || reproducible {
                log::debug!("attempt number {}", i+1);
                // Open a new connection if necessary
                if connect {
                    log::debug!("reconnecting...");
                    drop(&mut conn);
                    conn = match self.conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == self.cfg.opts.retries - 1 {
                                let _ = self.tx.clone().send(Err(error.into()));
                                if !reproducible {
                                    return;
                                }
                            }
                            i += 1;
                            continue;
                        }
                    };
                    self.write = true;
                }
                let commands = {
                    let term = self.term.clone();
                    self.encode(&term, false)
                };
                let opts = {
                    let term = self.opts.clone();
                    let res = self.encode(&term, true);
                    if res.is_empty() {
                        None
                    } else {
                        log::debug!("{}", res);
                        Some(res)
                    }
                };
                let mut query = wrap_query(QueryType::START, Some(commands), opts);
                log::debug!("{}", query);
                // Submit the query if necessary
                if self.write || reproducible {
                    log::debug!("submitting query");
                    if let Err(error) = write_query(&mut conn, &query) {
                        connect = true;
                        if i == self.cfg.opts.retries - 1 {
                            let _ = self.tx.clone().send(Err(error.into()));
                            if !reproducible {
                                return;
                            }
                        }
                        i += 1;
                        continue;
                    }
                    if reproducible {
                        connect = true;
                    } else {
                        connect = false;
                    }
                }
                // Handle the response
                let mut more = true;
                while more {
                    match self.process(&mut conn) {
                        Err(error) => {
                            if i == self.cfg.opts.retries - 1 || !self.retry {
                                let _ = self.tx.clone().send(Err(error.into()));
                                if !reproducible {
                                    return;
                                }
                            }
                            i += 1;
                            //continue;
                            more = false;
                            //break;
                        },
                        Ok(true) => { // Continue processing, for example in changefeeds
                            query = wrap_query(QueryType::CONTINUE, None, None);
                            if let Err(error) = write_query(&mut conn, &mut query) {
                                self.write = true;
                                self.retry = true;
                                let _ = self.tx.clone().send(Err(error.into()));
                                continue
                                //return Err(error)?;
                            }
                            //println!("Here is the problem!");
                        },
                        _ => {
                            more = false;
                            //break;
                        }, // Otherwise we are done processing, time to end
                    }
                }
                //break;
            }
        }
    }
    /// Process the results return either an error, or true if there was only a partial part
    /// of the message that got handled
    fn process(&mut self, conn: &mut Session ) -> Result<bool> {
        self.retry = false;
        self.write = false;
        match self.handle(conn) {
            Ok(t) => {
                match t {
                    Some(ResponseType::SUCCESS_PARTIAL) => {

                        return Ok(true);
                    }

                    Some(_) => { /* we are done */ }

                    None => {
                        let msg = String::from("Response::handle() unexpectedly returned None");
                        return Err(DriverError::Other(msg))?;
                    }
                }
            }
            Err(error) => {
                if error
                       .description()
                       .starts_with("Cannot perform write: primary replica for shard") {
                    self.write = true;
                    self.retry = true;
                }
                return Err(error)?;
            }
        }
        Ok(false)
    }

    fn handle(&mut self, conn: &mut Session) -> Result<Option<ResponseType>> {
        self.retry = false;
        //println!("size {:?}", self);
        match read_query(conn) {
            Ok(resp) => {
                let result: ReqlResponse = from_slice(&resp[..])?;
                let respt: ResponseType;
                if let Some(t) = ResponseType::from_i32(result.t) {
                    respt = t;
                } else {
                    let msg = format!("Unsupported response type ({}), returned by the database.", result.t);
                    return Err(DriverError::Other(msg))?;
                }
                // If the database says this response is an error convert the error
                // message to our native one.
                let has_generic_error = match respt {
                    ResponseType::CLIENT_ERROR |
                    ResponseType::COMPILE_ERROR |
                    ResponseType::RUNTIME_ERROR => true,
                    _ => false,
                };
                let mut msg = String::new();
                if result.e.is_some() || has_generic_error {
                    msg = if let Value::Array(error) = result.r.clone() {
                        if error.len() == 1 {
                            if let Some(Value::String(msg)) = error.into_iter().next() {
                                msg
                            } else {
                                return Err(ResponseError::Db(result.r))?;
                            }
                        } else {
                            return Err(ResponseError::Db(result.r))?;
                        }
                    } else {
                        return Err(ResponseError::Db(result.r))?;
                    };
                }
                if let Some(e) = result.e {
                    if let Some(error) = ErrorType::from_i32(e) {
                        match error {
                            ErrorType::INTERNAL => return Err(RuntimeError::Internal(msg))?,
                            ErrorType::RESOURCE_LIMIT => {
                                return Err(RuntimeError::ResourceLimit(msg))?
                            }
                            ErrorType::QUERY_LOGIC => return Err(RuntimeError::QueryLogic(msg))?,
                            ErrorType::NON_EXISTENCE => {
                                return Err(RuntimeError::NonExistence(msg))?
                            }
                            ErrorType::OP_FAILED => return Err(AvailabilityError::OpFailed(msg))?,
                            ErrorType::OP_INDETERMINATE => {
                                return Err(AvailabilityError::OpIndeterminate(msg))?
                            }
                            ErrorType::USER => return Err(RuntimeError::User(msg))?,
                            ErrorType::PERMISSION_ERROR => {
                                return Err(RuntimeError::Permission(msg))?
                            }
                        }
                    } else {
                        return Err(ResponseError::Db(result.r))?;
                    }
                }
                if has_generic_error {
                    match respt {
                        ResponseType::CLIENT_ERROR => return Err(DriverError::Other(msg))?,
                        ResponseType::COMPILE_ERROR => return Err(Error::Compile(msg))?,
                        ResponseType::RUNTIME_ERROR => return Err(ResponseError::Db(result.r))?,
                        _ => { /* not an error */ }
                    }
                }
                // Since this is a successful query let's process the results and send
                // them to the caller
                if let Ok(data) = from_value::<T>(result.r.clone()) {
                    let _ = self.tx.clone().send(Ok(Some(Document::Expected(data)))).wait();
                } else if let Ok(data) = from_value::<Vec<T>>(result.r.clone()) {
                    for v in data {
                        let _ = self.tx.clone().send(Ok(Some(Document::Expected(v)))).wait();
                    }
                }
                // Send unexpected query responses
                // This is not an error according to the database
                // but the caller wasn't expecting such a response
                // so we just return it raw.
                else if let Ok(data) = from_value::<Vec<Value>>(result.r.clone()) {
                    for v in data {
                        match v {
                            Value::Null => {
                                let _ = self.tx.clone().send(Ok(None)).wait();
                            }
                            value => {
                                // println!("got here");
                                let _ = self.tx.clone().send(Ok(Some(Document::Unexpected(value)))).wait();
                            }
                        }
                    }
                } else {
                    match result.r.clone() {
                        Value::Null => {
                            let _ = self.tx.clone().send(Ok(None)).wait();
                        }
                        value => {
                            let _ = self.tx.clone().send(Ok(Some(Document::Unexpected(value)))).wait();
                        }
                    }
                }
                // Return response type so we know if we need to retrieve more data
                Ok(Some(respt))
            }
            // We failed to read the server's response so we will
            // try again as long as we haven't used up all our allowed retries.
            Err(error) => {
                self.retry = true;
                return Err(error)?;
            }
        }
    }
}
<commit_msg>Fixed so submit threads actually exits<commit_after>use super::{read_query, wrap_query, write_query};
use crate::{
    Document, ReqlResponse, Request, Result,
    Session, SessionManager,
    errors::*,
};

use protobuf::ProtobufEnum;
use ql2::proto::{Query_QueryType as QueryType, Response_ErrorType as ErrorType,
                 Response_ResponseType as ResponseType};
use r2d2::PooledConnection;
use serde::de::DeserializeOwned;
use serde_json::{Value, from_slice, from_value};
use std::error::Error as StdError;
use futures::{Future, Sink};

impl<T: DeserializeOwned + Send + std::fmt::Debug> Request<T> {
    fn conn(&self) -> Result<PooledConnection<SessionManager>> {
        match self.pool.get() {
            Ok(mut conn) => {
                conn.id = conn.id.wrapping_add(1);
                Ok(conn)
            }
            Err(error) => Err(error)?,
        }
    }

    pub fn submit(mut self) {
        let mut conn = match self.conn() {
            Ok(conn) => conn,
            Err(error) => {
                let _ = self.tx.clone().send(Err(error));
                return;
            }
        };
        // Try sending the query
        log::debug!("submiting to server");
        {
            let mut i = 0;
            let mut connect = false;
            let reproducible = self.cfg.opts.reproducible;
            while i < self.cfg.opts.retries || reproducible {
                log::debug!("attempt number {}", i+1);
                // Open a new connection if necessary
                if connect {
                    log::debug!("reconnecting...");
                    drop(&mut conn);
                    conn = match self.conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == self.cfg.opts.retries - 1 {
                                let _ = self.tx.clone().send(Err(error.into()));
                                if !reproducible {
                                    return;
                                }
                            }
                            i += 1;
                            continue;
                        }
                    };
                    self.write = true;
                }
                let commands = {
                    let term = self.term.clone();
                    self.encode(&term, false)
                };
                let opts = {
                    let term = self.opts.clone();
                    let res = self.encode(&term, true);
                    if res.is_empty() {
                        None
                    } else {
                        log::debug!("{}", res);
                        Some(res)
                    }
                };
                let mut query = wrap_query(QueryType::START, Some(commands), opts);
                log::debug!("{}", query);
                // Submit the query if necessary
                if self.write || reproducible {
                    log::debug!("submitting query");
                    if let Err(error) = write_query(&mut conn, &query) {
                        connect = true;
                        if i == self.cfg.opts.retries - 1 {
                            let _ = self.tx.clone().send(Err(error.into()));
                            if !reproducible {
                                return;
                            }
                        }
                        i += 1;
                        continue;
                    }
                    if reproducible {
                        connect = true;
                    } else {
                        connect = false;
                    }
                }
                // Handle the response
                let mut more = true;
                while more {
                    match self.process(&mut conn) {
                        Err(error) => {
                            if i == self.cfg.opts.retries - 1 || !self.retry {
                                let _ = self.tx.clone().send(Err(error.into()));
                                if !reproducible {
                                    return;
                                }
                            }
                            i += 1;
                            //continue;
                            more = false;
                            break;
                        },
                        Ok(true) => { // Continue processing, for example in changefeeds
                            query = wrap_query(QueryType::CONTINUE, None, None);
                            if let Err(error) = write_query(&mut conn, &mut query) {
                                self.write = true;
                                self.retry = true;
                                let _ = self.tx.clone().send(Err(error.into()));
                                continue
                                //return Err(error)?;
                            }
                            //println!("Here is the problem!");
                        },
                        _ => {
                            more = false;
                            break;
                        }, // Otherwise we are done processing, time to end
                    }
                }
                if !more {
                    break;
                }
            }
        }
    }
    /// Process the results return either an error, or true if there was only a partial part
    /// of the message that got handled
    fn process(&mut self, conn: &mut Session ) -> Result<bool> {
        self.retry = false;
        self.write = false;
        match self.handle(conn) {
            Ok(t) => {
                match t {
                    Some(ResponseType::SUCCESS_PARTIAL) => {

                        return Ok(true);
                    }

                    Some(_) => { /* we are done */ }

                    None => {
                        let msg = String::from("Response::handle() unexpectedly returned None");
                        return Err(DriverError::Other(msg))?;
                    }
                }
            }
            Err(error) => {
                if error
                       .description()
                       .starts_with("Cannot perform write: primary replica for shard") {
                    self.write = true;
                    self.retry = true;
                }
                return Err(error)?;
            }
        }
        Ok(false)
    }

    fn handle(&mut self, conn: &mut Session) -> Result<Option<ResponseType>> {
        self.retry = false;
        //println!("size {:?}", self);
        match read_query(conn) {
            Ok(resp) => {
                let result: ReqlResponse = from_slice(&resp[..])?;
                let respt: ResponseType;
                if let Some(t) = ResponseType::from_i32(result.t) {
                    respt = t;
                } else {
                    let msg = format!("Unsupported response type ({}), returned by the database.", result.t);
                    return Err(DriverError::Other(msg))?;
                }
                // If the database says this response is an error convert the error
                // message to our native one.
                let has_generic_error = match respt {
                    ResponseType::CLIENT_ERROR |
                    ResponseType::COMPILE_ERROR |
                    ResponseType::RUNTIME_ERROR => true,
                    _ => false,
                };
                let mut msg = String::new();
                if result.e.is_some() || has_generic_error {
                    msg = if let Value::Array(error) = result.r.clone() {
                        if error.len() == 1 {
                            if let Some(Value::String(msg)) = error.into_iter().next() {
                                msg
                            } else {
                                return Err(ResponseError::Db(result.r))?;
                            }
                        } else {
                            return Err(ResponseError::Db(result.r))?;
                        }
                    } else {
                        return Err(ResponseError::Db(result.r))?;
                    };
                }
                if let Some(e) = result.e {
                    if let Some(error) = ErrorType::from_i32(e) {
                        match error {
                            ErrorType::INTERNAL => return Err(RuntimeError::Internal(msg))?,
                            ErrorType::RESOURCE_LIMIT => {
                                return Err(RuntimeError::ResourceLimit(msg))?
                            }
                            ErrorType::QUERY_LOGIC => return Err(RuntimeError::QueryLogic(msg))?,
                            ErrorType::NON_EXISTENCE => {
                                return Err(RuntimeError::NonExistence(msg))?
                            }
                            ErrorType::OP_FAILED => return Err(AvailabilityError::OpFailed(msg))?,
                            ErrorType::OP_INDETERMINATE => {
                                return Err(AvailabilityError::OpIndeterminate(msg))?
                            }
                            ErrorType::USER => return Err(RuntimeError::User(msg))?,
                            ErrorType::PERMISSION_ERROR => {
                                return Err(RuntimeError::Permission(msg))?
                            }
                        }
                    } else {
                        return Err(ResponseError::Db(result.r))?;
                    }
                }
                if has_generic_error {
                    match respt {
                        ResponseType::CLIENT_ERROR => return Err(DriverError::Other(msg))?,
                        ResponseType::COMPILE_ERROR => return Err(Error::Compile(msg))?,
                        ResponseType::RUNTIME_ERROR => return Err(ResponseError::Db(result.r))?,
                        _ => { /* not an error */ }
                    }
                }
                // Since this is a successful query let's process the results and send
                // them to the caller
                if let Ok(data) = from_value::<T>(result.r.clone()) {
                    let _ = self.tx.clone().send(Ok(Some(Document::Expected(data)))).wait();
                } else if let Ok(data) = from_value::<Vec<T>>(result.r.clone()) {
                    for v in data {
                        let _ = self.tx.clone().send(Ok(Some(Document::Expected(v)))).wait();
                    }
                }
                // Send unexpected query responses
                // This is not an error according to the database
                // but the caller wasn't expecting such a response
                // so we just return it raw.
                else if let Ok(data) = from_value::<Vec<Value>>(result.r.clone()) {
                    for v in data {
                        match v {
                            Value::Null => {
                                let _ = self.tx.clone().send(Ok(None)).wait();
                            }
                            value => {
                                // println!("got here");
                                let _ = self.tx.clone().send(Ok(Some(Document::Unexpected(value)))).wait();
                            }
                        }
                    }
                } else {
                    match result.r.clone() {
                        Value::Null => {
                            let _ = self.tx.clone().send(Ok(None)).wait();
                        }
                        value => {
                            let _ = self.tx.clone().send(Ok(Some(Document::Unexpected(value)))).wait();
                        }
                    }
                }
                // Return response type so we know if we need to retrieve more data
                Ok(Some(respt))
            }
            // We failed to read the server's response so we will
            // try again as long as we haven't used up all our allowed retries.
            Err(error) => {
                self.retry = true;
                return Err(error)?;
            }
        }
    }
}
<|endoftext|>