<commit_before>/// Wait on multiple concurrent branches, returning when **all** branches
/// complete with `Ok(_)` or on the first `Err(_)`.
///
/// The `try_join!` macro must be used inside of async functions, closures, and
/// blocks.
///
/// Similar to [`join!`], the `try_join!` macro takes a list of async
/// expressions and evaluates them concurrently on the same task. Each async
/// expression evaluates to a future and the futures from each expression are
/// multiplexed on the current task. The `try_join!` macro returns when **all**
/// branches return with `Ok` or when the **first** branch returns with `Err`.
///
/// [`join!`]: macro@join
///
/// # Notes
///
/// The supplied futures are stored inline and does not require allocating a
/// `Vec`.
///
/// ### Runtime characteristics
///
/// By running all async expressions on the current task, the expressions are
/// able to run **concurrently** but not in **parallel**. This means all
/// expressions are run on the same thread and if one branch blocks the thread,
/// all other expressions will be unable to continue. If parallelism is
/// required, spawn each async expression using [`tokio::spawn`] and pass the
/// join handle to `try_join!`.
///
/// [`tokio::spawn`]: crate::spawn
///
/// # Examples
///
/// Basic try_join with two branches.
///
/// ```
/// async fn do_stuff_async() -> Result<(), &'static str> {
///     // async work
/// # Ok(())
/// }
///
/// async fn more_async_work() -> Result<(), &'static str> {
///     // more here
/// # Ok(())
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let res = tokio::try_join!(
///         do_stuff_async(),
///         more_async_work());
///
///     match res {
///          Ok((first, second)) => {
///              // do something with the values
///          }
///          Err(err) => {
///             println!("processing failed; error = {}", err);
///          }
///     }
/// }
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
macro_rules! try_join {
    (@ {
        // One `_` for each branch in the `try_join!` macro. This is not used once
        // normalization is complete.
        ( $($count:tt)* )

        // Normalized try_join! branches
        $( ( $($skip:tt)* ) $e:expr, )*

    }) => {{
        use $crate::macros::support::{maybe_done, poll_fn, Future, Pin};
        use $crate::macros::support::Poll::{Ready, Pending};

        // Safety: nothing must be moved out of `futures`. This is to satisfy
        // the requirement of `Pin::new_unchecked` called below.
        let mut futures = ( $( maybe_done($e), )* );

        poll_fn(move |cx| {
            let mut is_pending = false;

            $(
                // Extract the future for this branch from the tuple.
                let ( $($skip,)* fut, .. ) = &mut futures;

                // Safety: future is stored on the stack above
                // and never moved.
                let mut fut = unsafe { Pin::new_unchecked(fut) };

                // Try polling
                if fut.as_mut().poll(cx).is_pending() {
                    is_pending = true;
                } else if fut.as_mut().output_mut().expect("expected completed future").is_err() {
                    return Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))
                }
            )*

            if is_pending {
                Pending
            } else {
                Ready(Ok(($({
                    // Extract the future for this branch from the tuple.
                    let ( $($skip,)* fut, .. ) = &mut futures;

                    // Safety: future is stored on the stack above
                    // and never moved.
                    let mut fut = unsafe { Pin::new_unchecked(fut) };

                    fut
                        .take_output()
                        .expect("expected completed future")
                        .ok()
                        .expect("expected Ok(_)")
                },)*)))
            }
        }).await
    }};

    // ===== Normalize =====

    (@ { ( $($s:tt)* ) $($t:tt)* } $e:expr, $($r:tt)* ) => {
        $crate::try_join!(@{ ($($s)* _) $($t)* ($($s)*) $e, } $($r)*)
    };

    // ===== Entry point =====

    ( $($e:expr),* $(,)?) => {
        $crate::try_join!(@{ () } $($e,)*)
    };
}
<commit_msg>docs: add returning on the first error example for try_join! (#4133)<commit_after>/// Wait on multiple concurrent branches, returning when **all** branches
/// complete with `Ok(_)` or on the first `Err(_)`.
///
/// The `try_join!` macro must be used inside of async functions, closures, and
/// blocks.
///
/// Similar to [`join!`], the `try_join!` macro takes a list of async
/// expressions and evaluates them concurrently on the same task. Each async
/// expression evaluates to a future and the futures from each expression are
/// multiplexed on the current task. The `try_join!` macro returns when **all**
/// branches return with `Ok` or when the **first** branch returns with `Err`.
///
/// [`join!`]: macro@join
///
/// # Notes
///
/// The supplied futures are stored inline and does not require allocating a
/// `Vec`.
///
/// ### Runtime characteristics
///
/// By running all async expressions on the current task, the expressions are
/// able to run **concurrently** but not in **parallel**. This means all
/// expressions are run on the same thread and if one branch blocks the thread,
/// all other expressions will be unable to continue. If parallelism is
/// required, spawn each async expression using [`tokio::spawn`] and pass the
/// join handle to `try_join!`.
///
/// [`tokio::spawn`]: crate::spawn
///
/// # Examples
///
/// Basic try_join with two branches.
///
/// ```
/// async fn do_stuff_async() -> Result<(), &'static str> {
///     // async work
/// # Ok(())
/// }
///
/// async fn more_async_work() -> Result<(), &'static str> {
///     // more here
/// # Ok(())
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let res = tokio::try_join!(
///         do_stuff_async(),
///         more_async_work());
///
///     match res {
///          Ok((first, second)) => {
///              // do something with the values
///          }
///          Err(err) => {
///             println!("processing failed; error = {}", err);
///          }
///     }
/// }
/// ```
///
/// Using `try_join!` with spawned tasks.
///
/// ```
/// use tokio::task::JoinHandle;
///
/// async fn do_stuff_async() -> Result<(), &'static str> {
///     // async work
/// # Err("failed")
/// }
///
/// async fn more_async_work() -> Result<(), &'static str> {
///     // more here
/// # Ok(())
/// }
///
/// async fn flatten<T>(handle: JoinHandle<Result<T, &'static str>>) -> Result<T, &'static str> {
///     match handle.await {
///         Ok(Ok(result)) => Ok(result),
///         Ok(Err(err)) => Err(err),
///         Err(err) => Err("handling failed"),
///     }
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let handle1 = tokio::spawn(do_stuff_async());
///     let handle2 = tokio::spawn(more_async_work());
///     match tokio::try_join!(flatten(handle1), flatten(handle2)) {
///         Ok(val) => {
///             // do something with the values
///         }
///         Err(err) => {
///             println!("Failed with {}.", err);
///             # assert_eq!(err, "failed");
///         }
///     }
/// }
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
macro_rules! try_join {
    (@ {
        // One `_` for each branch in the `try_join!` macro. This is not used once
        // normalization is complete.
        ( $($count:tt)* )

        // Normalized try_join! branches
        $( ( $($skip:tt)* ) $e:expr, )*

    }) => {{
        use $crate::macros::support::{maybe_done, poll_fn, Future, Pin};
        use $crate::macros::support::Poll::{Ready, Pending};

        // Safety: nothing must be moved out of `futures`. This is to satisfy
        // the requirement of `Pin::new_unchecked` called below.
        let mut futures = ( $( maybe_done($e), )* );

        poll_fn(move |cx| {
            let mut is_pending = false;

            $(
                // Extract the future for this branch from the tuple.
                let ( $($skip,)* fut, .. ) = &mut futures;

                // Safety: future is stored on the stack above
                // and never moved.
                let mut fut = unsafe { Pin::new_unchecked(fut) };

                // Try polling
                if fut.as_mut().poll(cx).is_pending() {
                    is_pending = true;
                } else if fut.as_mut().output_mut().expect("expected completed future").is_err() {
                    return Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))
                }
            )*

            if is_pending {
                Pending
            } else {
                Ready(Ok(($({
                    // Extract the future for this branch from the tuple.
                    let ( $($skip,)* fut, .. ) = &mut futures;

                    // Safety: future is stored on the stack above
                    // and never moved.
                    let mut fut = unsafe { Pin::new_unchecked(fut) };

                    fut
                        .take_output()
                        .expect("expected completed future")
                        .ok()
                        .expect("expected Ok(_)")
                },)*)))
            }
        }).await
    }};

    // ===== Normalize =====

    (@ { ( $($s:tt)* ) $($t:tt)* } $e:expr, $($r:tt)* ) => {
        $crate::try_join!(@{ ($($s)* _) $($t)* ($($s)*) $e, } $($r)*)
    };

    // ===== Entry point =====

    ( $($e:expr),* $(,)?) => {
        $crate::try_join!(@{ () } $($e,)*)
    };
}
<|endoftext|>


<commit_before>//! Methods to construct generic streaming and blocking unary operators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::nested::subgraph::{Source, Target};

use progress::count_map::CountMap;
use dataflow::operators::Notificator;
use progress::{Timestamp, Operate, Antichain};
use dataflow::channels::pushers::Tee;
use dataflow::channels::pushers::Counter as PushCounter;
use dataflow::channels::pushers::buffer::Buffer as PushBuffer;
use dataflow::channels::pact::ParallelizationContract;
use dataflow::channels::pullers::Counter as PullCounter;

use dataflow::operators::{InputHandle, OutputHandle};
use dataflow::operators::handles::{new_input_handle, new_output_handle};
use dataflow::operators::capability::mint as mint_capability;

use ::Data;

use dataflow::{Stream, Scope};

/// Methods to construct generic streaming and blocking unary operators.
pub trait Unary<G: Scope, D1: Data> {
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream and
    /// write to the output stream.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Unary};
    /// use timely::dataflow::channels::pact::Pipeline;
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .unary_stream(Pipeline, "example", |input, output| {
    ///                while let Some((time, data)) = input.next() {
    ///                    output.session(&time).give_content(data);
    ///                }
    ///            });
    /// });
    /// ```
    fn unary_stream<D2, L, P> (&self, pact: P, name: &str, logic: L) -> Stream<G, D2>
    where
        D2: Data,
        L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                 &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>)+'static,
        P: ParallelizationContract<G::Timestamp, D1>;
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream,
    /// write to the output stream, and request and receive notifications. The method also requires
    /// a vector of the initial notifications the operator requires (commonly none).
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Unary};
    /// use timely::dataflow::channels::pact::Pipeline;
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .unary_notify(Pipeline, "example", Vec::new(), |input, output, notificator| {
    ///                while let Some((time, data)) = input.next() {
    ///                    output.session(&time).give_content(data);
    ///                    notificator.notify_at(time);
    ///                }
    ///                while let Some((time, count)) = notificator.next() {
    ///                    println!("done with time: {:?}", time.time());
    ///                }
    ///            });
    /// });
    /// ```
    fn unary_notify<D2, L, P> (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2>
    where
        D2: Data,
        L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                 &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>,
                 &mut Notificator<G::Timestamp>)+'static,
         P: ParallelizationContract<G::Timestamp, D1>;
}

impl<G: Scope, D1: Data> Unary<G, D1> for Stream<G, D1> {
    fn unary_notify<D2: Data,
            L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                     &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2> {

        let mut scope = self.scope();   // clones the scope

        let channel_id = scope.new_identifier();

        let (sender, receiver) = pact.connect(&mut scope, channel_id);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let operator = Operator::new(PullCounter::new(receiver), targets, name.to_owned(), logic, Some((init, scope.peers())));
        let index = scope.add_operator(operator);

        self.connect_to(Target { index: index, port: 0 }, sender, channel_id);

        Stream::new(Source {index: index, port: 0 }, registrar, scope)
    }

    fn unary_stream<D2: Data,
             L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                      &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, mut logic: L) -> Stream<G, D2> {

        let mut scope = self.scope();

        let channel_id = scope.new_identifier();

        let (sender, receiver) = pact.connect(&mut scope, channel_id);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let operator = Operator::new(PullCounter::new(receiver), targets, name.to_owned(), move |i,o,_| logic(i,o), None);
        let index = scope.add_operator(operator);
        self.connect_to(Target { index: index, port: 0 }, sender, channel_id);

        Stream::new(Source { index: index, port: 0 }, registrar, scope)
    }
}

struct Operator
    <
    T: Timestamp,
    D1: Data,
    D2: Data,
    L: FnMut(&mut InputHandle<T, D1>,
             &mut OutputHandle<T, D2, Tee<T, D2>>,
             &mut Notificator<T>)> {
    name:             String,
    input:            PullCounter<T, D1>,
    output:           PushBuffer<T, D2, PushCounter<T, D2, Tee<T, D2>>>,
    notificator:      Notificator<T>,
    logic:            L,
    notify:           Option<(Vec<T>, usize)>,    // initial notifications and peers
    internal_changes: Rc<RefCell<CountMap<T>>>,
}

impl<T:  Timestamp,
     D1: Data,
     D2: Data,
     L:  FnMut(&mut InputHandle<T, D1>,
               &mut OutputHandle<T, D2, Tee<T, D2>>,
               &mut Notificator<T>)>
Operator<T, D1, D2, L> {
    pub fn new(receiver: PullCounter<T, D1>,
               targets:  Tee<T, D2>,
               name:     String,
               logic:    L,
               notify:   Option<(Vec<T>, usize)>)
           -> Operator<T, D1, D2, L> {

        Operator {
            name:    name,
            input:       receiver,
            output:      PushBuffer::new(PushCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
            notificator: Notificator::new(),
            logic:   logic,
            notify:  notify,
            internal_changes: Rc::new(RefCell::new(CountMap::new())),
        }
    }
}

impl<T, D1, D2, L> Operate<T> for Operator<T, D1, D2, L>
where T: Timestamp,
      D1: Data, D2: Data,
      L: FnMut(&mut InputHandle<T, D1>,
               &mut OutputHandle<T, D2, Tee<T, D2>>,
               &mut Notificator<T>) {
    fn inputs(&self) -> usize { 1 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        // by the end of the method, we want the return Vec<CountMap<T>> to contain each reserved capability,
        // *multiplied by the number of peers*. This is so that each worker knows to wait for each other worker
        // instance. Importantly, we do not want to multiply the number of capabilities by the number of peers.

        let mut internal = vec![CountMap::new()];
        if let Some((ref mut initial, peers)) = self.notify {
            for time in initial.drain(..) {
                self.notificator.notify_at(mint_capability(time, self.internal_changes.clone()));
            }

            // augment the counts for each reserved capability.
            for &(ref time, count) in self.internal_changes.borrow().iter() {
                internal[0].update(time, count * (peers as i64 - 1));
            }

            // drain the changes to empty out, and complete the counts for internal.
            self.internal_changes.borrow_mut().drain_into(&mut internal[0]);
        }
        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>,
                                       frontier: &mut [CountMap<T>]) {
        self.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) {
        self.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, consumed: &mut [CountMap<T>],
                                         internal: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        {
            let mut input_handle = new_input_handle(&mut self.input, self.internal_changes.clone());
            let mut output_handle = new_output_handle(&mut self.output);
            (self.logic)(&mut input_handle, &mut output_handle, &mut self.notificator);
        }

        self.output.cease();

        // extract what we know about progress from the input and output adapters.
        self.input.pull_progress(&mut consumed[0]);
        self.output.inner().pull_progress(&mut produced[0]);
        self.internal_changes.borrow_mut().drain_into(&mut internal[0]);

        false   // no unannounced internal work
    }

    fn name(&self) -> String { self.name.clone() }
    fn notify_me(&self) -> bool { self.notify.is_some() }
}
<commit_msg>removed stray space<commit_after>//! Methods to construct generic streaming and blocking unary operators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::nested::subgraph::{Source, Target};

use progress::count_map::CountMap;
use dataflow::operators::Notificator;
use progress::{Timestamp, Operate, Antichain};
use dataflow::channels::pushers::Tee;
use dataflow::channels::pushers::Counter as PushCounter;
use dataflow::channels::pushers::buffer::Buffer as PushBuffer;
use dataflow::channels::pact::ParallelizationContract;
use dataflow::channels::pullers::Counter as PullCounter;

use dataflow::operators::{InputHandle, OutputHandle};
use dataflow::operators::handles::{new_input_handle, new_output_handle};
use dataflow::operators::capability::mint as mint_capability;

use ::Data;

use dataflow::{Stream, Scope};

/// Methods to construct generic streaming and blocking unary operators.
pub trait Unary<G: Scope, D1: Data> {
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream and
    /// write to the output stream.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Unary};
    /// use timely::dataflow::channels::pact::Pipeline;
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .unary_stream(Pipeline, "example", |input, output| {
    ///                while let Some((time, data)) = input.next() {
    ///                    output.session(&time).give_content(data);
    ///                }
    ///            });
    /// });
    /// ```
    fn unary_stream<D2, L, P> (&self, pact: P, name: &str, logic: L) -> Stream<G, D2>
    where
        D2: Data,
        L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                 &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>)+'static,
        P: ParallelizationContract<G::Timestamp, D1>;
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream,
    /// write to the output stream, and request and receive notifications. The method also requires
    /// a vector of the initial notifications the operator requires (commonly none).
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Unary};
    /// use timely::dataflow::channels::pact::Pipeline;
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .unary_notify(Pipeline, "example", Vec::new(), |input, output, notificator| {
    ///                while let Some((time, data)) = input.next() {
    ///                    output.session(&time).give_content(data);
    ///                    notificator.notify_at(time);
    ///                }
    ///                while let Some((time, count)) = notificator.next() {
    ///                    println!("done with time: {:?}", time.time());
    ///                }
    ///            });
    /// });
    /// ```
    fn unary_notify<D2, L, P>(&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2>
    where
        D2: Data,
        L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                 &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>,
                 &mut Notificator<G::Timestamp>)+'static,
         P: ParallelizationContract<G::Timestamp, D1>;
}

impl<G: Scope, D1: Data> Unary<G, D1> for Stream<G, D1> {
    fn unary_notify<D2: Data,
            L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                     &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2> {

        let mut scope = self.scope();   // clones the scope

        let channel_id = scope.new_identifier();

        let (sender, receiver) = pact.connect(&mut scope, channel_id);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let operator = Operator::new(PullCounter::new(receiver), targets, name.to_owned(), logic, Some((init, scope.peers())));
        let index = scope.add_operator(operator);

        self.connect_to(Target { index: index, port: 0 }, sender, channel_id);

        Stream::new(Source {index: index, port: 0 }, registrar, scope)
    }

    fn unary_stream<D2: Data,
             L: FnMut(&mut InputHandle<G::Timestamp, D1>,
                      &mut OutputHandle<G::Timestamp, D2, Tee<G::Timestamp, D2>>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, mut logic: L) -> Stream<G, D2> {

        let mut scope = self.scope();

        let channel_id = scope.new_identifier();

        let (sender, receiver) = pact.connect(&mut scope, channel_id);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let operator = Operator::new(PullCounter::new(receiver), targets, name.to_owned(), move |i,o,_| logic(i,o), None);
        let index = scope.add_operator(operator);
        self.connect_to(Target { index: index, port: 0 }, sender, channel_id);

        Stream::new(Source { index: index, port: 0 }, registrar, scope)
    }
}

struct Operator
    <
    T: Timestamp,
    D1: Data,
    D2: Data,
    L: FnMut(&mut InputHandle<T, D1>,
             &mut OutputHandle<T, D2, Tee<T, D2>>,
             &mut Notificator<T>)> {
    name:             String,
    input:            PullCounter<T, D1>,
    output:           PushBuffer<T, D2, PushCounter<T, D2, Tee<T, D2>>>,
    notificator:      Notificator<T>,
    logic:            L,
    notify:           Option<(Vec<T>, usize)>,    // initial notifications and peers
    internal_changes: Rc<RefCell<CountMap<T>>>,
}

impl<T:  Timestamp,
     D1: Data,
     D2: Data,
     L:  FnMut(&mut InputHandle<T, D1>,
               &mut OutputHandle<T, D2, Tee<T, D2>>,
               &mut Notificator<T>)>
Operator<T, D1, D2, L> {
    pub fn new(receiver: PullCounter<T, D1>,
               targets:  Tee<T, D2>,
               name:     String,
               logic:    L,
               notify:   Option<(Vec<T>, usize)>)
           -> Operator<T, D1, D2, L> {

        Operator {
            name:    name,
            input:       receiver,
            output:      PushBuffer::new(PushCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
            notificator: Notificator::new(),
            logic:   logic,
            notify:  notify,
            internal_changes: Rc::new(RefCell::new(CountMap::new())),
        }
    }
}

impl<T, D1, D2, L> Operate<T> for Operator<T, D1, D2, L>
where T: Timestamp,
      D1: Data, D2: Data,
      L: FnMut(&mut InputHandle<T, D1>,
               &mut OutputHandle<T, D2, Tee<T, D2>>,
               &mut Notificator<T>) {
    fn inputs(&self) -> usize { 1 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        // by the end of the method, we want the return Vec<CountMap<T>> to contain each reserved capability,
        // *multiplied by the number of peers*. This is so that each worker knows to wait for each other worker
        // instance. Importantly, we do not want to multiply the number of capabilities by the number of peers.

        let mut internal = vec![CountMap::new()];
        if let Some((ref mut initial, peers)) = self.notify {
            for time in initial.drain(..) {
                self.notificator.notify_at(mint_capability(time, self.internal_changes.clone()));
            }

            // augment the counts for each reserved capability.
            for &(ref time, count) in self.internal_changes.borrow().iter() {
                internal[0].update(time, count * (peers as i64 - 1));
            }

            // drain the changes to empty out, and complete the counts for internal.
            self.internal_changes.borrow_mut().drain_into(&mut internal[0]);
        }
        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>,
                                       frontier: &mut [CountMap<T>]) {
        self.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) {
        self.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, consumed: &mut [CountMap<T>],
                                         internal: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        {
            let mut input_handle = new_input_handle(&mut self.input, self.internal_changes.clone());
            let mut output_handle = new_output_handle(&mut self.output);
            (self.logic)(&mut input_handle, &mut output_handle, &mut self.notificator);
        }

        self.output.cease();

        // extract what we know about progress from the input and output adapters.
        self.input.pull_progress(&mut consumed[0]);
        self.output.inner().pull_progress(&mut produced[0]);
        self.internal_changes.borrow_mut().drain_into(&mut internal[0]);

        false   // no unannounced internal work
    }

    fn name(&self) -> String { self.name.clone() }
    fn notify_me(&self) -> bool { self.notify.is_some() }
}
<|endoftext|>


<commit_before>use crate::beacon_chain::BeaconChain;
use crate::error;
use crate::messages::NodeMessage;
use crate::service::{NetworkMessage, OutgoingMessage};
use crate::sync::SimpleSync;
use crossbeam_channel::{unbounded as channel, Sender};
use futures::future;
use futures::prelude::*;
use libp2p::{
    rpc::{RPCMethod, RPCRequest, RPCResponse},
    HelloMessage, PeerId, RPCEvent,
};
use slog::warn;
use slog::{debug, trace};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::Hash256;

/// Timeout for RPC requests.
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
/// Timeout before banning a peer for non-identification.
const HELLO_TIMEOUT: Duration = Duration::from_secs(30);

/// Handles messages received from the network and client and organises syncing.
pub struct MessageHandler {
    /// Currently loaded and initialised beacon chain.
    chain: Arc<BeaconChain>,
    /// The syncing framework.
    sync: SimpleSync,
    /// The network channel to relay messages to the Network service.
    network_send: crossbeam_channel::Sender<NetworkMessage>,
    /// A mapping of peers and the RPC id we have sent an RPC request to.
    requests: HashMap<(PeerId, u64), Instant>,
    /// A counter of request id for each peer.
    request_ids: HashMap<PeerId, u64>,
    /// The `MessageHandler` logger.
    log: slog::Logger,
}

/// Types of messages the handler can receive.
#[derive(Debug, Clone)]
pub enum HandlerMessage {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// A Node message has been received.
    Message(PeerId, NodeMessage),
    /// An RPC response/request has been received.
    RPC(PeerId, RPCEvent),
}

impl MessageHandler {
    /// Initializes and runs the MessageHandler.
    pub fn new(
        beacon_chain: Arc<BeaconChain>,
        network_send: crossbeam_channel::Sender<NetworkMessage>,
        executor: &tokio::runtime::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<Sender<HandlerMessage>> {
        debug!(log, "Service starting");

        let (handler_send, handler_recv) = channel();

        // Initialise sync and begin processing in thread
        // generate the Message handler
        let sync = SimpleSync::new(beacon_chain.clone(), &log);

        let mut handler = MessageHandler {
            // TODO: The handler may not need a chain, perhaps only sync?
            chain: beacon_chain.clone(),
            sync,
            network_send,
            requests: HashMap::new(),
            request_ids: HashMap::new(),

            log: log.clone(),
        };

        // spawn handler task
        // TODO: Handle manual termination of thread
        executor.spawn(future::poll_fn(move || -> Result<_, _> {
            loop {
                handler.handle_message(handler_recv.recv().map_err(|_| {
                    debug!(log, "Network message handler terminated.");
                })?);
            }
        }));

        Ok(handler_send)
    }

    /// Handle all messages incoming from the network service.
    fn handle_message(&mut self, message: HandlerMessage) {
        match message {
            // we have initiated a connection to a peer
            HandlerMessage::PeerDialed(peer_id) => {
                let id = self.generate_request_id(&peer_id);
                self.send_hello(peer_id, id, true);
            }
            // we have received an RPC message request/response
            HandlerMessage::RPC(peer_id, rpc_event) => {
                self.handle_rpc_message(peer_id, rpc_event);
            }
            //TODO: Handle all messages
            _ => {}
        }
    }

    /* RPC - Related functionality */

    /// Handle RPC messages
    fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) {
        match rpc_message {
            RPCEvent::Request {
                id,
                method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point.
                body,
            } => self.handle_rpc_request(peer_id, id, body),
            RPCEvent::Response {
                id,
                method_id: _,
                result,
            } => self.handle_rpc_response(peer_id, id, result),
        }
    }

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {
        match request {
            RPCRequest::Hello(hello_message) => {
                self.handle_hello_request(peer_id, id, hello_message)
            }
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {
        // if response id is related to a request, ignore (likely RPC timeout)
        if self.requests.remove(&(peer_id, id)).is_none() {
            return;
        }
    }

    /// Handle a HELLO RPC request message.
    fn handle_hello_request(&mut self, peer_id: PeerId, id: u64, hello_message: HelloMessage) {
        // send back a HELLO message
        self.send_hello(peer_id.clone(), id, false);
        // validate the peer
        if !self.sync.validate_peer(peer_id.clone(), hello_message) {
            debug!(
                self.log,
                "Peer dropped due to mismatching HELLO messages: {:?}", peer_id
            );
            //TODO: block/ban the peer
        }
    }

    /// Handle a HELLO RPC response message.
    fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) {
        debug!(self.log, "Hello response received from peer: {:?}", peer_id);
        // validate peer - decide whether to drop/ban or add to sync
        // TODO: Peer validation
    }

    /* General RPC helper functions */

    /// Generates a new request id for a peer.
    fn generate_request_id(&mut self, peer_id: &PeerId) -> u64 {
        // generate a unique id for the peer
        let id = {
            let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0);
            let id = borrowed_id.clone();
            //increment the counter
            *borrowed_id += 1;
            id
        };
        // register RPC request
        self.requests.insert((peer_id.clone(), id), Instant::now());
        debug!(
            self.log,
            "Hello request registered with peer: {:?}", peer_id
        );
        id
    }

    /// Sends a HELLO RPC request or response to a newly connected peer.
    //TODO: The boolean determines if sending request/respond, will be cleaner in the RPC re-write
    fn send_hello(&mut self, peer_id: PeerId, id: u64, request: bool) {
        let rpc_event = match request {
            true => RPCEvent::Request {
                id,
                method_id: RPCMethod::Hello.into(),
                body: RPCRequest::Hello(self.sync.generate_hello()),
            },
            false => RPCEvent::Response {
                id,
                method_id: RPCMethod::Hello.into(),
                result: RPCResponse::Hello(self.sync.generate_hello()),
            },
        };

        // send the hello request to the network
        trace!(self.log, "Sending HELLO message to peer {:?}", peer_id);
        self.send_rpc(peer_id, rpc_event);
    }

    /// Sends an RPC request/response to the network server.
    fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.network_send
            .send(NetworkMessage::Send(
                peer_id,
                OutgoingMessage::RPC(rpc_event),
            ))
            .unwrap_or_else(|_| {
                warn!(
                    self.log,
                    "Could not send RPC message to the network service"
                )
            });
    }
}
<commit_msg>Add peer validation and successful handshake<commit_after>use crate::beacon_chain::BeaconChain;
use crate::error;
use crate::messages::NodeMessage;
use crate::service::{NetworkMessage, OutgoingMessage};
use crate::sync::SimpleSync;
use crossbeam_channel::{unbounded as channel, Sender};
use futures::future;
use futures::prelude::*;
use libp2p::{
    rpc::{RPCMethod, RPCRequest, RPCResponse},
    HelloMessage, PeerId, RPCEvent,
};
use slog::warn;
use slog::{debug, trace};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::Hash256;

/// Timeout for RPC requests.
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
/// Timeout before banning a peer for non-identification.
const HELLO_TIMEOUT: Duration = Duration::from_secs(30);

/// Handles messages received from the network and client and organises syncing.
pub struct MessageHandler {
    /// Currently loaded and initialised beacon chain.
    chain: Arc<BeaconChain>,
    /// The syncing framework.
    sync: SimpleSync,
    /// The network channel to relay messages to the Network service.
    network_send: crossbeam_channel::Sender<NetworkMessage>,
    /// A mapping of peers and the RPC id we have sent an RPC request to.
    requests: HashMap<(PeerId, u64), Instant>,
    /// A counter of request id for each peer.
    request_ids: HashMap<PeerId, u64>,
    /// The `MessageHandler` logger.
    log: slog::Logger,
}

/// Types of messages the handler can receive.
#[derive(Debug, Clone)]
pub enum HandlerMessage {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// A Node message has been received.
    Message(PeerId, NodeMessage),
    /// An RPC response/request has been received.
    RPC(PeerId, RPCEvent),
}

impl MessageHandler {
    /// Initializes and runs the MessageHandler.
    pub fn new(
        beacon_chain: Arc<BeaconChain>,
        network_send: crossbeam_channel::Sender<NetworkMessage>,
        executor: &tokio::runtime::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<Sender<HandlerMessage>> {
        debug!(log, "Service starting");

        let (handler_send, handler_recv) = channel();

        // Initialise sync and begin processing in thread
        // generate the Message handler
        let sync = SimpleSync::new(beacon_chain.clone(), &log);

        let mut handler = MessageHandler {
            // TODO: The handler may not need a chain, perhaps only sync?
            chain: beacon_chain.clone(),
            sync,
            network_send,
            requests: HashMap::new(),
            request_ids: HashMap::new(),

            log: log.clone(),
        };

        // spawn handler task
        // TODO: Handle manual termination of thread
        executor.spawn(future::poll_fn(move || -> Result<_, _> {
            loop {
                handler.handle_message(handler_recv.recv().map_err(|_| {
                    debug!(log, "Network message handler terminated.");
                })?);
            }
        }));

        Ok(handler_send)
    }

    /// Handle all messages incoming from the network service.
    fn handle_message(&mut self, message: HandlerMessage) {
        match message {
            // we have initiated a connection to a peer
            HandlerMessage::PeerDialed(peer_id) => {
                let id = self.generate_request_id(&peer_id);
                self.send_hello(peer_id, id, true);
            }
            // we have received an RPC message request/response
            HandlerMessage::RPC(peer_id, rpc_event) => {
                self.handle_rpc_message(peer_id, rpc_event);
            }
            //TODO: Handle all messages
            _ => {}
        }
    }

    /* RPC - Related functionality */

    /// Handle RPC messages
    fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) {
        match rpc_message {
            RPCEvent::Request {
                id,
                method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point.
                body,
            } => self.handle_rpc_request(peer_id, id, body),
            RPCEvent::Response {
                id,
                method_id: _,
                result,
            } => self.handle_rpc_response(peer_id, id, result),
        }
    }

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {
        match request {
            RPCRequest::Hello(hello_message) => {
                self.handle_hello_request(peer_id, id, hello_message)
            }
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {
        // if response id is related to a request, ignore (likely RPC timeout)
        if self
            .requests
            .remove(&(peer_id.clone(), id.clone()))
            .is_none()
        {
            debug!(self.log, "Unrecognized response from peer: {:?}", peer_id);
            return;
        }
        match response {
            RPCResponse::Hello(hello_message) => {
                debug!(self.log, "Hello response received from peer: {:?}", peer_id);
                self.validate_hello(peer_id, hello_message);
            }
        }
    }

    /// Handle a HELLO RPC request message.
    fn handle_hello_request(&mut self, peer_id: PeerId, id: u64, hello_message: HelloMessage) {
        // send back a HELLO message
        self.send_hello(peer_id.clone(), id, false);
        // validate the peer
        self.validate_hello(peer_id, hello_message);
    }

    /// Validate a HELLO RPC message.
    fn validate_hello(&mut self, peer_id: PeerId, message: HelloMessage) {
        // validate the peer
        if !self.sync.validate_peer(peer_id.clone(), message) {
            debug!(
                self.log,
                "Peer dropped due to mismatching HELLO messages: {:?}", peer_id
            );
            //TODO: block/ban the peer
        }
    }

    /* General RPC helper functions */

    /// Generates a new request id for a peer.
    fn generate_request_id(&mut self, peer_id: &PeerId) -> u64 {
        // generate a unique id for the peer
        let id = {
            let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0);
            let id = borrowed_id.clone();
            //increment the counter
            *borrowed_id += 1;
            id
        };
        // register RPC request
        self.requests.insert((peer_id.clone(), id), Instant::now());
        debug!(
            self.log,
            "Hello request registered with peer: {:?}", peer_id
        );
        id
    }

    /// Sends a HELLO RPC request or response to a newly connected peer.
    //TODO: The boolean determines if sending request/respond, will be cleaner in the RPC re-write
    fn send_hello(&mut self, peer_id: PeerId, id: u64, request: bool) {
        let rpc_event = match request {
            true => RPCEvent::Request {
                id,
                method_id: RPCMethod::Hello.into(),
                body: RPCRequest::Hello(self.sync.generate_hello()),
            },
            false => RPCEvent::Response {
                id,
                method_id: RPCMethod::Hello.into(),
                result: RPCResponse::Hello(self.sync.generate_hello()),
            },
        };

        // send the hello request to the network
        trace!(self.log, "Sending HELLO message to peer {:?}", peer_id);
        self.send_rpc(peer_id, rpc_event);
    }

    /// Sends an RPC request/response to the network server.
    fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.network_send
            .send(NetworkMessage::Send(
                peer_id,
                OutgoingMessage::RPC(rpc_event),
            ))
            .unwrap_or_else(|_| {
                warn!(
                    self.log,
                    "Could not send RPC message to the network service"
                )
            });
    }
}
<|endoftext|>


<commit_before>use glib::translate::*;
use glib_sys;
use libc;
use node::*;
use std::collections::HashMap;
use super::*;
use util;

#[allow(improper_ctypes)]
extern "C" {
    fn rsvg_new_filter_primitive_blend(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_color_matrix(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_component_transfer(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_composite(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_convolve_matrix(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_diffuse_lighting(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_displacement_map(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_node_light_source(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_flood(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_node_component_transfer_function(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_gaussian_blur(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_image(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_merge(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_erode(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_merge_node(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_offset(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_specular_lighting(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_tile(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_turbulence(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
}

type NodeCreateFn = unsafe extern "C" fn(*const libc::c_char, *const RsvgNode) -> *const RsvgNode;

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        h.insert("a",                   (true,  rsvg_node_link_new as NodeCreateFn));
        /* h.insert("altGlyph",         (true,   as NodeCreateFn)); */
        /* h.insert("altGlyphDef",      (false,  as NodeCreateFn)); */
        /* h.insert("altGlyphItem",     (false,  as NodeCreateFn)); */
        /* h.insert("animate",          (false,  as NodeCreateFn)); */
        /* h.insert("animateColor",     (false,  as NodeCreateFn)); */
        /* h.insert("animateMotion",    (false,  as NodeCreateFn)); */
        /* h.insert("animateTransform", (false,  as NodeCreateFn)); */
        h.insert("circle",              (true,  rsvg_node_circle_new as NodeCreateFn));
        h.insert("clipPath",            (true,  rsvg_node_clip_path_new as NodeCreateFn));
        /* h.insert("color-profile",    (false,  as NodeCreateFn)); */
        h.insert("conicalGradient",     (true,  rsvg_node_radial_gradient_new as NodeCreateFn));
        /* h.insert("cursor",           (false,  as NodeCreateFn)); */
        h.insert("defs",                (true,  rsvg_node_defs_new as NodeCreateFn));
        /* h.insert("desc",             (true,   as NodeCreateFn)); */
        h.insert("ellipse",             (true,  rsvg_node_ellipse_new as NodeCreateFn));
        h.insert("feBlend",             (true,  rsvg_new_filter_primitive_blend as NodeCreateFn));
        h.insert("feColorMatrix",       (true,  rsvg_new_filter_primitive_color_matrix as NodeCreateFn));
        h.insert("feComponentTransfer", (true,  rsvg_new_filter_primitive_component_transfer as NodeCreateFn));
        h.insert("feComposite",         (true,  rsvg_new_filter_primitive_composite as NodeCreateFn));
        h.insert("feConvolveMatrix",    (true,  rsvg_new_filter_primitive_convolve_matrix as NodeCreateFn));
        h.insert("feDiffuseLighting",   (true,  rsvg_new_filter_primitive_diffuse_lighting as NodeCreateFn));
        h.insert("feDisplacementMap",   (true,  rsvg_new_filter_primitive_displacement_map as NodeCreateFn));
        h.insert("feDistantLight",      (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feFlood",             (true,  rsvg_new_filter_primitive_flood as NodeCreateFn));
        h.insert("feFuncA",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncB",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncG",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncR",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feGaussianBlur",      (true,  rsvg_new_filter_primitive_gaussian_blur as NodeCreateFn));
        h.insert("feImage",             (true,  rsvg_new_filter_primitive_image as NodeCreateFn));
        h.insert("feMerge",             (true,  rsvg_new_filter_primitive_merge as NodeCreateFn));
        h.insert("feMergeNode",         (false, rsvg_new_filter_primitive_merge_node as NodeCreateFn));
        h.insert("feMorphology",        (true,  rsvg_new_filter_primitive_erode as NodeCreateFn));
        h.insert("feOffset",            (true,  rsvg_new_filter_primitive_offset as NodeCreateFn));
        h.insert("fePointLight",        (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feSpecularLighting",  (true,  rsvg_new_filter_primitive_specular_lighting as NodeCreateFn));
        h.insert("feSpotLight",         (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feTile",              (true,  rsvg_new_filter_primitive_tile as NodeCreateFn));
        h.insert("feTurbulence",        (true,  rsvg_new_filter_primitive_turbulence as NodeCreateFn));
        h.insert("filter",              (true,  rsvg_new_filter as NodeCreateFn));
        /* h.insert("font",             (true,   as NodeCreateFn)); */
        /* h.insert("font-face",        (false,  as NodeCreateFn)); */
        /* h.insert("font-face-format", (false,  as NodeCreateFn)); */
        /* h.insert("font-face-name",   (false,  as NodeCreateFn)); */
        /* h.insert("font-face-src",    (false,  as NodeCreateFn)); */
        /* h.insert("font-face-uri",    (false,  as NodeCreateFn)); */
        /* h.insert("foreignObject",    (true,   as NodeCreateFn)); */
        h.insert("g",                   (true,  rsvg_node_group_new as NodeCreateFn));
        /* h.insert("glyph",            (true,   as NodeCreateFn)); */
        /* h.insert("glyphRef",         (true,   as NodeCreateFn)); */
        /* h.insert("hkern",            (false,  as NodeCreateFn)); */
        h.insert("image",               (true,  rsvg_node_image_new as NodeCreateFn));
        h.insert("line",                (true,  rsvg_node_line_new as NodeCreateFn));
        h.insert("linearGradient",      (true,  rsvg_node_linear_gradient_new as NodeCreateFn));
        h.insert("marker",              (true,  rsvg_node_marker_new as NodeCreateFn));
        h.insert("mask",                (true,  rsvg_node_mask_new as NodeCreateFn));
        /* h.insert("metadata",         (false,  as NodeCreateFn)); */
        /* h.insert("missing-glyph",    (true,   as NodeCreateFn)); */
        /* h.insert("mpath",            (false,  as NodeCreateFn)); */
        h.insert("multiImage",          (false, rsvg_node_switch_new as NodeCreateFn)); /* hack to make multiImage sort-of work */
        h.insert("path",                (true,  rsvg_node_path_new as NodeCreateFn));
        h.insert("pattern",             (true,  rsvg_node_pattern_new as NodeCreateFn));
        h.insert("polygon",             (true,  rsvg_node_polygon_new as NodeCreateFn));
        h.insert("polyline",            (true,  rsvg_node_polyline_new as NodeCreateFn));
        h.insert("radialGradient",      (true,  rsvg_node_radial_gradient_new as NodeCreateFn));
        h.insert("rect",                (true,  rsvg_node_rect_new as NodeCreateFn));
        /* h.insert("script",           (false,  as NodeCreateFn)); */
        /* h.insert("set",              (false,  as NodeCreateFn)); */
        h.insert("stop",                (true,  rsvg_node_stop_new as NodeCreateFn));
        /* h.insert("style",            (false,  as NodeCreateFn)); */
        h.insert("subImage",            (false, rsvg_node_group_new as NodeCreateFn));
        h.insert("subImageRef",         (false, rsvg_node_image_new as NodeCreateFn));
        h.insert("svg",                 (true,  rsvg_node_svg_new as NodeCreateFn));
        h.insert("switch",              (true,  rsvg_node_switch_new as NodeCreateFn));
        h.insert("symbol",              (true,  rsvg_node_symbol_new as NodeCreateFn));
        h.insert("text",                (true,  rsvg_node_text_new as NodeCreateFn));
        /* h.insert("textPath",         (true,   as NodeCreateFn)); */
        /* h.insert("title",            (true,   as NodeCreateFn)); */
        h.insert("tref",                (true,  rsvg_node_tref_new as NodeCreateFn));
        h.insert("tspan",               (true,  rsvg_node_tspan_new as NodeCreateFn));
        h.insert("use",                 (true,  rsvg_node_use_new as NodeCreateFn));
        /* h.insert("view",             (false,  as NodeCreateFn)); */
        /* h.insert("vkern",            (false,  as NodeCreateFn)); */
        h
    };
}

#[no_mangle]
pub extern "C" fn rsvg_load_new_node(
    _name: *const libc::c_char,
    parent: *const RsvgNode,
    supports_class_attribute: *mut glib_sys::gboolean
) -> *const RsvgNode {
    assert!(!_name.is_null());
    assert!(!supports_class_attribute.is_null());

    let name = unsafe { util::utf8_cstr(_name) };
    let creator = match NODE_CREATORS.get(name) {
        Some(c) => c,
        /* Whenever we encounter a node we don't understand, represent it as a defs.
         * This is like a group, but it doesn't do any rendering of children.  The
         * effect is that we will ignore all children of unknown elements.
         */
        None => &(true, rsvg_node_defs_new as NodeCreateFn)
    };

    unsafe {
        *supports_class_attribute = creator.0.to_glib();
        creator.1(_name, parent)
    }
}
<commit_msg>rustfmt<commit_after>use super::*;
use glib::translate::*;
use glib_sys;
use libc;
use node::*;
use std::collections::HashMap;
use util;

#[allow(improper_ctypes)]
extern "C" {
    fn rsvg_new_filter_primitive_blend(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_color_matrix(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_component_transfer(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_composite(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_convolve_matrix(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_diffuse_lighting(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_displacement_map(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_node_light_source(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_flood(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_node_component_transfer_function(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_gaussian_blur(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_image(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_merge(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_erode(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_merge_node(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_offset(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_specular_lighting(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_tile(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter_primitive_turbulence(
        _: *const libc::c_char,
        _: *const RsvgNode,
    ) -> *const RsvgNode;
    fn rsvg_new_filter(_: *const libc::c_char, _: *const RsvgNode) -> *const RsvgNode;
}

type NodeCreateFn = unsafe extern "C" fn(*const libc::c_char, *const RsvgNode) -> *const RsvgNode;

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        h.insert("a",                   (true,  rsvg_node_link_new as NodeCreateFn));
        /* h.insert("altGlyph",         (true,   as NodeCreateFn)); */
        /* h.insert("altGlyphDef",      (false,  as NodeCreateFn)); */
        /* h.insert("altGlyphItem",     (false,  as NodeCreateFn)); */
        /* h.insert("animate",          (false,  as NodeCreateFn)); */
        /* h.insert("animateColor",     (false,  as NodeCreateFn)); */
        /* h.insert("animateMotion",    (false,  as NodeCreateFn)); */
        /* h.insert("animateTransform", (false,  as NodeCreateFn)); */
        h.insert("circle",              (true,  rsvg_node_circle_new as NodeCreateFn));
        h.insert("clipPath",            (true,  rsvg_node_clip_path_new as NodeCreateFn));
        /* h.insert("color-profile",    (false,  as NodeCreateFn)); */
        h.insert("conicalGradient",     (true,  rsvg_node_radial_gradient_new as NodeCreateFn));
        /* h.insert("cursor",           (false,  as NodeCreateFn)); */
        h.insert("defs",                (true,  rsvg_node_defs_new as NodeCreateFn));
        /* h.insert("desc",             (true,   as NodeCreateFn)); */
        h.insert("ellipse",             (true,  rsvg_node_ellipse_new as NodeCreateFn));
        h.insert("feBlend",             (true,  rsvg_new_filter_primitive_blend as NodeCreateFn));
        h.insert("feColorMatrix",       (true,  rsvg_new_filter_primitive_color_matrix as NodeCreateFn));
        h.insert("feComponentTransfer", (true,  rsvg_new_filter_primitive_component_transfer as NodeCreateFn));
        h.insert("feComposite",         (true,  rsvg_new_filter_primitive_composite as NodeCreateFn));
        h.insert("feConvolveMatrix",    (true,  rsvg_new_filter_primitive_convolve_matrix as NodeCreateFn));
        h.insert("feDiffuseLighting",   (true,  rsvg_new_filter_primitive_diffuse_lighting as NodeCreateFn));
        h.insert("feDisplacementMap",   (true,  rsvg_new_filter_primitive_displacement_map as NodeCreateFn));
        h.insert("feDistantLight",      (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feFlood",             (true,  rsvg_new_filter_primitive_flood as NodeCreateFn));
        h.insert("feFuncA",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncB",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncG",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feFuncR",             (false, rsvg_new_node_component_transfer_function as NodeCreateFn));
        h.insert("feGaussianBlur",      (true,  rsvg_new_filter_primitive_gaussian_blur as NodeCreateFn));
        h.insert("feImage",             (true,  rsvg_new_filter_primitive_image as NodeCreateFn));
        h.insert("feMerge",             (true,  rsvg_new_filter_primitive_merge as NodeCreateFn));
        h.insert("feMergeNode",         (false, rsvg_new_filter_primitive_merge_node as NodeCreateFn));
        h.insert("feMorphology",        (true,  rsvg_new_filter_primitive_erode as NodeCreateFn));
        h.insert("feOffset",            (true,  rsvg_new_filter_primitive_offset as NodeCreateFn));
        h.insert("fePointLight",        (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feSpecularLighting",  (true,  rsvg_new_filter_primitive_specular_lighting as NodeCreateFn));
        h.insert("feSpotLight",         (false, rsvg_new_node_light_source as NodeCreateFn));
        h.insert("feTile",              (true,  rsvg_new_filter_primitive_tile as NodeCreateFn));
        h.insert("feTurbulence",        (true,  rsvg_new_filter_primitive_turbulence as NodeCreateFn));
        h.insert("filter",              (true,  rsvg_new_filter as NodeCreateFn));
        /* h.insert("font",             (true,   as NodeCreateFn)); */
        /* h.insert("font-face",        (false,  as NodeCreateFn)); */
        /* h.insert("font-face-format", (false,  as NodeCreateFn)); */
        /* h.insert("font-face-name",   (false,  as NodeCreateFn)); */
        /* h.insert("font-face-src",    (false,  as NodeCreateFn)); */
        /* h.insert("font-face-uri",    (false,  as NodeCreateFn)); */
        /* h.insert("foreignObject",    (true,   as NodeCreateFn)); */
        h.insert("g",                   (true,  rsvg_node_group_new as NodeCreateFn));
        /* h.insert("glyph",            (true,   as NodeCreateFn)); */
        /* h.insert("glyphRef",         (true,   as NodeCreateFn)); */
        /* h.insert("hkern",            (false,  as NodeCreateFn)); */
        h.insert("image",               (true,  rsvg_node_image_new as NodeCreateFn));
        h.insert("line",                (true,  rsvg_node_line_new as NodeCreateFn));
        h.insert("linearGradient",      (true,  rsvg_node_linear_gradient_new as NodeCreateFn));
        h.insert("marker",              (true,  rsvg_node_marker_new as NodeCreateFn));
        h.insert("mask",                (true,  rsvg_node_mask_new as NodeCreateFn));
        /* h.insert("metadata",         (false,  as NodeCreateFn)); */
        /* h.insert("missing-glyph",    (true,   as NodeCreateFn)); */
        /* h.insert("mpath",            (false,  as NodeCreateFn)); */
        h.insert("multiImage",          (false, rsvg_node_switch_new as NodeCreateFn)); /* hack to make multiImage sort-of work */
        h.insert("path",                (true,  rsvg_node_path_new as NodeCreateFn));
        h.insert("pattern",             (true,  rsvg_node_pattern_new as NodeCreateFn));
        h.insert("polygon",             (true,  rsvg_node_polygon_new as NodeCreateFn));
        h.insert("polyline",            (true,  rsvg_node_polyline_new as NodeCreateFn));
        h.insert("radialGradient",      (true,  rsvg_node_radial_gradient_new as NodeCreateFn));
        h.insert("rect",                (true,  rsvg_node_rect_new as NodeCreateFn));
        /* h.insert("script",           (false,  as NodeCreateFn)); */
        /* h.insert("set",              (false,  as NodeCreateFn)); */
        h.insert("stop",                (true,  rsvg_node_stop_new as NodeCreateFn));
        /* h.insert("style",            (false,  as NodeCreateFn)); */
        h.insert("subImage",            (false, rsvg_node_group_new as NodeCreateFn));
        h.insert("subImageRef",         (false, rsvg_node_image_new as NodeCreateFn));
        h.insert("svg",                 (true,  rsvg_node_svg_new as NodeCreateFn));
        h.insert("switch",              (true,  rsvg_node_switch_new as NodeCreateFn));
        h.insert("symbol",              (true,  rsvg_node_symbol_new as NodeCreateFn));
        h.insert("text",                (true,  rsvg_node_text_new as NodeCreateFn));
        /* h.insert("textPath",         (true,   as NodeCreateFn)); */
        /* h.insert("title",            (true,   as NodeCreateFn)); */
        h.insert("tref",                (true,  rsvg_node_tref_new as NodeCreateFn));
        h.insert("tspan",               (true,  rsvg_node_tspan_new as NodeCreateFn));
        h.insert("use",                 (true,  rsvg_node_use_new as NodeCreateFn));
        /* h.insert("view",             (false,  as NodeCreateFn)); */
        /* h.insert("vkern",            (false,  as NodeCreateFn)); */
        h
    };
}

#[no_mangle]
pub extern "C" fn rsvg_load_new_node(
    _name: *const libc::c_char,
    parent: *const RsvgNode,
    supports_class_attribute: *mut glib_sys::gboolean,
) -> *const RsvgNode {
    assert!(!_name.is_null());
    assert!(!supports_class_attribute.is_null());

    let name = unsafe { util::utf8_cstr(_name) };
    let creator = match NODE_CREATORS.get(name) {
        Some(c) => c,
        // Whenever we encounter a node we don't understand, represent it as a defs.
        // This is like a group, but it doesn't do any rendering of children.  The
        // effect is that we will ignore all children of unknown elements.
        //
        None => &(true, rsvg_node_defs_new as NodeCreateFn),
    };

    unsafe {
        *supports_class_attribute = creator.0.to_glib();
        creator.1(_name, parent)
    }
}
<|endoftext|>


<commit_before>use crate::utils::span_lint_and_sugg;
use crate::utils::sugg::format_numeric_literal;
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
use std::f32;
use std::f64;
use std::fmt;
use syntax::ast::*;

declare_clippy_lint! {
    /// **What it does:** Checks for float literals with a precision greater
    /// than that supported by the underlying type
    ///
    /// **Why is this bad?** Rust will truncate the literal silently.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// let v: f32 = 0.123_456_789_9;
    /// println!("{}", v); //  0.123_456_789
    ///
    /// // Good
    /// let v: f64 = 0.123_456_789_9;
    /// println!("{}", v); //  0.123_456_789_9
    /// ```
    pub EXCESSIVE_PRECISION,
    style,
    "excessive precision for float literal"
}

declare_lint_pass!(ExcessivePrecision => [EXCESSIVE_PRECISION]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
        if_chain! {
            let ty = cx.tables.expr_ty(expr);
            if let ty::Float(fty) = ty.kind;
            if let hir::ExprKind::Lit(ref lit) = expr.kind;
            if let LitKind::Float(sym, _) = lit.node;
            if let Some(sugg) = Self::check(sym, fty);
            then {
                span_lint_and_sugg(
                    cx,
                    EXCESSIVE_PRECISION,
                    expr.span,
                    "float has excessive precision",
                    "consider changing the type or truncating it to",
                    sugg,
                    Applicability::MachineApplicable,
                );
            }
        }
    }
}

impl ExcessivePrecision {
    // None if nothing to lint, Some(suggestion) if lint necessary
    #[must_use]
    fn check(sym: Symbol, fty: FloatTy) -> Option<String> {
        let max = max_digits(fty);
        let sym_str = sym.as_str();
        if dot_zero_exclusion(&sym_str) {
            return None;
        }
        // Try to bail out if the float is for sure fine.
        // If its within the 2 decimal digits of being out of precision we
        // check if the parsed representation is the same as the string
        // since we'll need the truncated string anyway.
        let digits = count_digits(&sym_str);
        if digits > max as usize {
            let formatter = FloatFormat::new(&sym_str);
            let sr = match fty {
                FloatTy::F32 => sym_str.parse::<f32>().map(|f| formatter.format(f)),
                FloatTy::F64 => sym_str.parse::<f64>().map(|f| formatter.format(f)),
            };
            // We know this will parse since we are in LatePass
            let s = sr.unwrap();

            if sym_str == s {
                None
            } else {
                Some(format_numeric_literal(&s, None, true))
            }
        } else {
            None
        }
    }
}

/// Should we exclude the float because it has a `.0` or `.` suffix
/// Ex `1_000_000_000.0`
/// Ex `1_000_000_000.`
#[must_use]
fn dot_zero_exclusion(s: &str) -> bool {
    s.split('.').nth(1).map_or(false, |after_dec| {
        let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');

        match decpart.next() {
            Some('0') => decpart.count() == 0,
            Some(_) => false,
            None => true,
        }
    })
}

#[must_use]
fn max_digits(fty: FloatTy) -> u32 {
    match fty {
        FloatTy::F32 => f32::DIGITS,
        FloatTy::F64 => f64::DIGITS,
    }
}

/// Counts the digits excluding leading zeros
#[must_use]
fn count_digits(s: &str) -> usize {
    // Note that s does not contain the f32/64 suffix, and underscores have been stripped
    s.chars()
        .filter(|c| *c != '-' && *c != '.')
        .take_while(|c| *c != 'e' && *c != 'E')
        .fold(0, |count, c| {
            // leading zeros
            if c == '0' && count == 0 {
                count
            } else {
                count + 1
            }
        })
}

enum FloatFormat {
    LowerExp,
    UpperExp,
    Normal,
}
impl FloatFormat {
    #[must_use]
    fn new(s: &str) -> Self {
        s.chars()
            .find_map(|x| match x {
                'e' => Some(Self::LowerExp),
                'E' => Some(Self::UpperExp),
                _ => None,
            })
            .unwrap_or(Self::Normal)
    }
    fn format<T>(&self, f: T) -> String
    where
        T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
    {
        match self {
            Self::LowerExp => format!("{:e}", f),
            Self::UpperExp => format!("{:E}", f),
            Self::Normal => format!("{}", f),
        }
    }
}
<commit_msg>Add lint to detect lossy float literals<commit_after>use crate::utils::span_lint_and_sugg;
use crate::utils::sugg::format_numeric_literal;
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::{f32, f64, fmt};
use syntax::ast::*;

declare_clippy_lint! {
    /// **What it does:** Checks for float literals with a precision greater
    /// than that supported by the underlying type.
    ///
    /// **Why is this bad?** Rust will silently lose precision during conversion
    /// to a float.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// let v: f32 = 0.123_456_789_9;
    /// println!("{}", v); //  0.123_456_789
    ///
    /// // Good
    /// let v: f64 = 0.123_456_789_9;
    /// println!("{}", v); //  0.123_456_789_9
    /// ```
    pub EXCESSIVE_PRECISION,
    style,
    "excessive precision for float literal"
}

declare_lint_pass!(ExcessivePrecision => [EXCESSIVE_PRECISION]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
        if_chain! {
            let ty = cx.tables.expr_ty(expr);
            if let ty::Float(fty) = ty.kind;
            if let hir::ExprKind::Lit(ref lit) = expr.kind;
            if let LitKind::Float(sym, lit_float_ty) = lit.node;
            then {
                let sym_str = sym.as_str();
                let formatter = FloatFormat::new(&sym_str);
                // Try to bail out if the float is for sure fine.
                // If its within the 2 decimal digits of being out of precision we
                // check if the parsed representation is the same as the string
                // since we'll need the truncated string anyway.
                let digits = count_digits(&sym_str);
                let max = max_digits(fty);
                let float_str = match fty {
                    FloatTy::F32 => sym_str.parse::<f32>().map(|f| formatter.format(f)),
                    FloatTy::F64 => sym_str.parse::<f64>().map(|f| formatter.format(f)),
                }.unwrap();
                let type_suffix = match lit_float_ty {
                    LitFloatType::Suffixed(FloatTy::F32) => Some("f32"),
                    LitFloatType::Suffixed(FloatTy::F64) => Some("f64"),
                    _ => None
                };

                if is_whole_number(&sym_str, fty) {
                    // Normalize the literal by stripping the fractional portion
                    if sym_str.split('.').next().unwrap() != float_str {
                        span_lint_and_sugg(
                            cx,
                            EXCESSIVE_PRECISION,
                            expr.span,
                            "literal cannot be represented as the underlying type without loss of precision",
                            "consider changing the type or replacing it with",
                            format_numeric_literal(format!("{}.0", float_str).as_str(), type_suffix, true),
                            Applicability::MachineApplicable,
                        );
                    }
                } else if digits > max as usize && sym_str != float_str {
                    span_lint_and_sugg(
                        cx,
                        EXCESSIVE_PRECISION,
                        expr.span,
                        "float has excessive precision",
                        "consider changing the type or truncating it to",
                        format_numeric_literal(&float_str, type_suffix, true),
                        Applicability::MachineApplicable,
                    );
                }
            }
        }
    }
}

// Checks whether a float literal is a whole number
#[must_use]
fn is_whole_number(sym_str: &str, fty: FloatTy) -> bool {
    match fty {
        FloatTy::F32 => sym_str.parse::<f32>().unwrap().fract() == 0.0,
        FloatTy::F64 => sym_str.parse::<f64>().unwrap().fract() == 0.0,
    }
}

#[must_use]
fn max_digits(fty: FloatTy) -> u32 {
    match fty {
        FloatTy::F32 => f32::DIGITS,
        FloatTy::F64 => f64::DIGITS,
    }
}

/// Counts the digits excluding leading zeros
#[must_use]
fn count_digits(s: &str) -> usize {
    // Note that s does not contain the f32/64 suffix, and underscores have been stripped
    s.chars()
        .filter(|c| *c != '-' && *c != '.')
        .take_while(|c| *c != 'e' && *c != 'E')
        .fold(0, |count, c| {
            // leading zeros
            if c == '0' && count == 0 {
                count
            } else {
                count + 1
            }
        })
}

enum FloatFormat {
    LowerExp,
    UpperExp,
    Normal,
}
impl FloatFormat {
    #[must_use]
    fn new(s: &str) -> Self {
        s.chars()
            .find_map(|x| match x {
                'e' => Some(Self::LowerExp),
                'E' => Some(Self::UpperExp),
                _ => None,
            })
            .unwrap_or(Self::Normal)
    }
    fn format<T>(&self, f: T) -> String
    where
        T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
    {
        match self {
            Self::LowerExp => format!("{:e}", f),
            Self::UpperExp => format!("{:E}", f),
            Self::Normal => format!("{}", f),
        }
    }
}
<|endoftext|>


<commit_before>use libc;

use std::ffi::CStr;
use std::str;

// In paint servers (patterns, gradients, etc.), we have an
// Option<String> for fallback names.  This is a utility function to
// clone one of those.
pub fn clone_fallback_name(fallback: &Option<String>) -> Option<String> {
    if let Some(ref fallback_name) = *fallback {
        Some(fallback_name.clone())
    } else {
        None
    }
}

pub const DBL_EPSILON: f64 = 1e-10;

pub fn double_equals(a: f64, b: f64) -> bool {
    (a - b).abs() < DBL_EPSILON
}

/// Converts a `char *` which is known to be valid UTF-8 into a `&str`
///
/// The usual `from_glib_none(s)` allocates an owned String.  The
/// purpose of `utf8_cstr()` is to get a temporary string slice into a
/// C string which is already known to be valid UTF-8; for example,
/// as for strings which come from `libxml2`.
pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
    assert!(!s.is_null());

    str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes())
}
<commit_msg>util.rs: Make DBL_EPSILON private; we'll remove it soon<commit_after>use libc;

use std::ffi::CStr;
use std::str;

// In paint servers (patterns, gradients, etc.), we have an
// Option<String> for fallback names.  This is a utility function to
// clone one of those.
pub fn clone_fallback_name(fallback: &Option<String>) -> Option<String> {
    if let Some(ref fallback_name) = *fallback {
        Some(fallback_name.clone())
    } else {
        None
    }
}

const DBL_EPSILON: f64 = 1e-10;

pub fn double_equals(a: f64, b: f64) -> bool {
    (a - b).abs() < DBL_EPSILON
}

/// Converts a `char *` which is known to be valid UTF-8 into a `&str`
///
/// The usual `from_glib_none(s)` allocates an owned String.  The
/// purpose of `utf8_cstr()` is to get a temporary string slice into a
/// C string which is already known to be valid UTF-8; for example,
/// as for strings which come from `libxml2`.
pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
    assert!(!s.is_null());

    str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes())
}
<|endoftext|>


<commit_before>use codec::{eyre::Result, utils::vec_string, Codec, CodecTrait, DecodeOptions, EncodeOptions};
use stencila_schema::Node;

#[cfg(feature = "decode")]
mod decode;

#[cfg(feature = "decode")]
pub use decode::decode_fragment;

#[cfg(feature = "encode")]
mod encode;

#[cfg(feature = "encode")]
pub use encode::{wrap_standalone, EncodeContext, ToHtml};

/// A codec for HTML
pub struct HtmlCodec {}

impl CodecTrait for HtmlCodec {
    fn spec() -> Codec {
        Codec {
            formats: vec_string!["html"],
            root_types: vec_string!["*"],
            from_string: cfg!(feature = "decode"),
            from_path: cfg!(feature = "decode"),
            to_string: cfg!(feature = "encode"),
            to_path: cfg!(feature = "encode"),
            ..Default::default()
        }
    }

    #[cfg(feature = "decode")]
    fn from_str(str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        decode::decode(str, None)
    }

    #[cfg(feature = "encode")]
    fn to_string(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        encode::encode(node, options)
    }
}
<commit_msg>chore(HTML codec): Set status to beta<commit_after>use codec::{eyre::Result, utils::vec_string, Codec, CodecTrait, DecodeOptions, EncodeOptions};
use stencila_schema::Node;

#[cfg(feature = "decode")]
mod decode;

#[cfg(feature = "decode")]
pub use decode::decode_fragment;

#[cfg(feature = "encode")]
mod encode;

#[cfg(feature = "encode")]
pub use encode::{wrap_standalone, EncodeContext, ToHtml};

/// A codec for HTML
pub struct HtmlCodec {}

impl CodecTrait for HtmlCodec {
    fn spec() -> Codec {
        Codec {
            status: "beta".to_string(),
            formats: vec_string!["html"],
            root_types: vec_string!["*"],
            from_string: cfg!(feature = "decode"),
            from_path: cfg!(feature = "decode"),
            to_string: cfg!(feature = "encode"),
            to_path: cfg!(feature = "encode"),
            ..Default::default()
        }
    }

    #[cfg(feature = "decode")]
    fn from_str(str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        decode::decode(str, None)
    }

    #[cfg(feature = "encode")]
    fn to_string(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        encode::encode(node, options)
    }
}
<|endoftext|>


<commit_before>const RELOCATABLE_FILE_TYPE: u16 = 1;
const EXECUTABLE_FILE_TYPE: u16 = 2;

const ELF_MACHINE_386: u16 = 3;

const ELF_CURRENT_VERSION: u32 = 1;

#[derive(Debug, Clone)]
struct ElfHeader {
    /// Elf file identifier
    ident: [u8; 16],
    /// File type, either relocatable object file or executable
    file_type: u16,
    /// Machine type
    machine: u16,
    /// Elf format version
    version: u32,
    /// Address of entry point, 0 if no associated entry point exists
    entry_address: u32,
    /// Program header table file offset, 0 if no table
    program_header_offset: u32,
    /// Section header table file offset, 0 if no table
    section_header_offset: u32,
    /// Processor specific flags
    flags: u32,
    /// Elf header size in bytes
    elf_header_size: u16,
    /// Size of one entry in program header table
    program_header_size: u16,
    /// Number of entries in program header table
    program_header_count: u16,
    /// Size of one entry in section header table
    section_header_size: u16,
    /// Number of entries in section header table
    section_header_count: u16,
    /// Index of entry in section header table that holds string table.
    /// SHN_UNDEF if string table does not exist.
    string_table_index: u16,
}

const ELF_IDENT: [u8; 16] = [
    0x7f, b'E', b'L', b'F', // EI_MAG0 to EI_MAG3
    1, // EI_CLASS, always 32-bit
    1, // EI_DATA, ELFDATA2LSB for little endian encoding
    ELF_CURRENT_VERSION, // EI_VERSION
    0, 0, 0, 0, 0, 0, 0, 0, 0, // EI_PAD, padding bytes
];
<commit_msg>kill the elves<commit_after><|endoftext|>


<commit_before>use std::io;
use std::str;
use super::r2d2;
use super::serde_json::error as json;

quick_error! {
    /// The most generic error message in ReQL
    #[derive(Debug)]
    pub enum Error {
        Compile(descr: String) { }
        Runtime(err: RuntimeError) { from() }
        Driver(err: DriverError) { from() }
    }
}

quick_error! {
    /// The parent class of all runtime errors
    ///
    /// All errors on the server unrelated to compilation. Programs may use this to catch any runtime
    /// error, but the server will always return a more specific error class.
    #[derive(Debug)]
    pub enum RuntimeError {
        QueryLogic(err: QueryLogicError) { from() }
        ResourceLimit(descr: String) {}
        User(descr: String) {}
        Internal(descr: String) {}
        Timeout(descr: String) {}
        Availability(err: AvailabilityError) { from() }
        Permissions(descr: String) {}
    }
}

quick_error! {
    /// The query contains a logical impossibility, such as adding a number to a string.
    #[derive(Debug)]
    pub enum QueryLogicError {
        NonExistence(descr: String) {}
    }
}

quick_error! {
    /// A server in the cluster is unavailable
    ///
    /// The parent class of `OpFailedError` and `OpIndeterminateError`. Programs may use this
    /// to catch any availability error, but the server will always return one of this class’s
    /// children.
    #[derive(Debug)]
    pub enum AvailabilityError {
        OpFailed(descr: String) {}
        OpIndeterminate(descr: String) {}
    }
}

quick_error! {
    /// An error has occurred within the driver
    ///
    /// This may be a driver bug, or it may be an unfulfillable command, such as an unserializable
    /// query.
    #[derive(Debug)]
    pub enum DriverError {
        Auth(descr: String) {}
        Initialization(err: r2d2::InitializationError) { from() }
        Connection(err: ConnectionError) { from() }
        ParseResponse(err: str::Utf8Error) { from() }
        Json(err: json::Error) { from() }
    }
}

quick_error! {
    /// Connection related errors
    #[derive(Debug)]
    pub enum ConnectionError {
        PoolWrite(descr: String) {}
        PoolRead(descr: String) {}
        Io(err: io::Error) { from() }
        Other(descr: String) {}
    }
}

/// Converts from r2d2 error
impl From<r2d2::InitializationError> for Error {
    fn from(err: r2d2::InitializationError) -> Error {
        From::from(DriverError::Initialization(err))
    }
}

impl From<ConnectionError> for Error {
    fn from(err: ConnectionError) -> Error {
        From::from(DriverError::Connection(err))
    }
}

/// Converts from IO error
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        From::from(ConnectionError::Io(err))
    }
}

/// Converts from Utf8Error error
impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        From::from(DriverError::ParseResponse(err))
    }
}

/// Converts from serde_json error
impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        From::from(DriverError::Json(err))
    }
}
<commit_msg>Print useful information on panicking<commit_after>use std::io;
use std::str;
use super::r2d2;
use super::serde_json::error as json;

quick_error! {
    /// The most generic error message in ReQL
    #[derive(Debug)]
    pub enum Error {
        Compile(descr: String) {
            display("{}", descr)
        }
        Runtime(err: RuntimeError) {
            from()
            description(err.description())
            cause(err)
            display("{:?}", err)
        }
        Driver(err: DriverError) {
            from()
            description(err.description())
            cause(err)
            display("{:?}", err)
        }
    }
}

quick_error! {
    /// The parent class of all runtime errors
    ///
    /// All errors on the server unrelated to compilation. Programs may use this to catch any runtime
    /// error, but the server will always return a more specific error class.
    #[derive(Debug)]
    pub enum RuntimeError {
        QueryLogic(err: QueryLogicError) { from() }
        ResourceLimit(descr: String)
        User(descr: String)
        Internal(descr: String)
        Timeout(descr: String)
        Availability(err: AvailabilityError) { from() }
        Permissions(descr: String)
    }
}

quick_error! {
    /// The query contains a logical impossibility, such as adding a number to a string.
    #[derive(Debug)]
    pub enum QueryLogicError {
        NonExistence(descr: String)
    }
}

quick_error! {
    /// A server in the cluster is unavailable
    ///
    /// The parent class of `OpFailedError` and `OpIndeterminateError`. Programs may use this
    /// to catch any availability error, but the server will always return one of this class’s
    /// children.
    #[derive(Debug)]
    pub enum AvailabilityError {
        OpFailed(descr: String)
        OpIndeterminate(descr: String)
    }
}

quick_error! {
    /// An error has occurred within the driver
    ///
    /// This may be a driver bug, or it may be an unfulfillable command, such as an unserializable
    /// query.
    #[derive(Debug)]
    pub enum DriverError {
        Auth(descr: String)
        Connection(err: ConnectionError) { from() }
        ParseResponse(err: str::Utf8Error) { from() }
        Json(err: json::Error) { from() }
    }
}

quick_error! {
    /// Connection related errors
    #[derive(Debug)]
    pub enum ConnectionError {
        Initialization(err: r2d2::InitializationError) { from() }
        PoolWrite(descr: String)
        PoolRead(descr: String)
        Io(err: io::Error) { from() }
        Other(descr: String)
    }
}

/// Converts from r2d2 error
impl From<r2d2::InitializationError> for Error {
    fn from(err: r2d2::InitializationError) -> Error {
        From::from(ConnectionError::Initialization(err))
    }
}

impl From<ConnectionError> for Error {
    fn from(err: ConnectionError) -> Error {
        From::from(DriverError::Connection(err))
    }
}

/// Converts from IO error
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        From::from(ConnectionError::Io(err))
    }
}

/// Converts from Utf8Error error
impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        From::from(DriverError::ParseResponse(err))
    }
}

/// Converts from serde_json error
impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        From::from(DriverError::Json(err))
    }
}
<|endoftext|>