<commit_before>use crate::types::GossipKind;
use crate::Enr;
use libp2p::discv5::{Discv5Config, Discv5ConfigBuilder};
use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId};
use libp2p::Multiaddr;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::time::Duration;

pub const GOSSIP_MAX_SIZE: usize = 1_048_576;

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// The address to broadcast to peers about which address we are listening on. None indicates
    /// that no discovery address has been set in the CLI args.
    pub enr_address: Option<std::net::IpAddr>,

    /// The udp port to broadcast to peers in order to reach back for discovery.
    pub enr_udp_port: Option<u16>,

    /// The tcp port to broadcast to peers in order to reach back for libp2p services.
    pub enr_tcp_port: Option<u16>,

    /// Target number of connected peers.
    pub max_peers: usize,

    /// A secp256k1 secret key, as bytes in ASCII-encoded hex.
    ///
    /// With or without `0x` prefix.
    #[serde(skip)]
    pub secret_key_hex: Option<String>,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// Discv5 configuration parameters.
    #[serde(skip)]
    pub discv5_config: Discv5Config,

    /// List of nodes to initially connect to.
    pub boot_nodes: Vec<Enr>,

    /// List of libp2p nodes to initially connect to.
    pub libp2p_nodes: Vec<Multiaddr>,

    /// Client version
    pub client_version: String,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<GossipKind>,

    /// Introduces randomization in network propagation of messages. This should only be set for
    /// testing purposes and will likely be removed in future versions.
    // TODO: Remove this functionality for mainnet
    pub propagation_percentage: Option<u8>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");

        // The default topics that we will initially subscribe to
        let topics = vec![
            GossipKind::BeaconBlock,
            GossipKind::BeaconAggregateAndProof,
            GossipKind::VoluntaryExit,
            GossipKind::ProposerSlashing,
            GossipKind::AttesterSlashing,
        ];

        // The function used to generate a gossipsub message id
        // We use base64(SHA256(data)) for content addressing
        let gossip_message_id = |message: &GossipsubMessage| {
            MessageId(base64::encode_config(
                &Sha256::digest(&message.data),
                base64::URL_SAFE,
            ))
        };

        // gossipsub configuration
        // Note: The topics by default are sent as plain strings. Hashes are an optional
        // parameter.
        let gs_config = GossipsubConfigBuilder::new()
            .max_transmit_size(GOSSIP_MAX_SIZE)
            .heartbeat_interval(Duration::from_secs(1))
            .manual_propagation() // require validation before propagation
            .no_source_id()
            .message_id_fn(gossip_message_id)
            .build();

        // discv5 configuration
        let discv5_config = Discv5ConfigBuilder::new()
            .request_timeout(Duration::from_secs(4))
            .request_retries(2)
            .enr_update(true) // update IP based on PONG responses
            .enr_peer_update_min(2) // prevents NAT's should be raised for mainnet
            .query_parallelism(5)
            .query_timeout(Duration::from_secs(60))
            .query_peer_timeout(Duration::from_secs(2))
            .ip_limit(false) // limits /24 IP's in buckets. Enable for mainnet
            .ping_interval(Duration::from_secs(300))
            .build();

        // NOTE: Some of these get overridden by the corresponding CLI default values.
        Config {
            network_dir,
            listen_address: "0.0.0.0".parse().expect("valid ip address"),
            libp2p_port: 9000,
            discovery_port: 9000,
            enr_address: None,
            enr_udp_port: None,
            enr_tcp_port: None,
            max_peers: 50,
            secret_key_hex: None,
            gs_config,
            discv5_config,
            boot_nodes: vec![],
            libp2p_nodes: vec![],
            client_version: version::version(),
            topics,
            propagation_percentage: None,
        }
    }
}
<commit_msg>Remove padding from gossipsub ids (#1083)<commit_after>use crate::types::GossipKind;
use crate::Enr;
use libp2p::discv5::{Discv5Config, Discv5ConfigBuilder};
use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId};
use libp2p::Multiaddr;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::time::Duration;

pub const GOSSIP_MAX_SIZE: usize = 1_048_576;

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// The address to broadcast to peers about which address we are listening on. None indicates
    /// that no discovery address has been set in the CLI args.
    pub enr_address: Option<std::net::IpAddr>,

    /// The udp port to broadcast to peers in order to reach back for discovery.
    pub enr_udp_port: Option<u16>,

    /// The tcp port to broadcast to peers in order to reach back for libp2p services.
    pub enr_tcp_port: Option<u16>,

    /// Target number of connected peers.
    pub max_peers: usize,

    /// A secp256k1 secret key, as bytes in ASCII-encoded hex.
    ///
    /// With or without `0x` prefix.
    #[serde(skip)]
    pub secret_key_hex: Option<String>,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// Discv5 configuration parameters.
    #[serde(skip)]
    pub discv5_config: Discv5Config,

    /// List of nodes to initially connect to.
    pub boot_nodes: Vec<Enr>,

    /// List of libp2p nodes to initially connect to.
    pub libp2p_nodes: Vec<Multiaddr>,

    /// Client version
    pub client_version: String,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<GossipKind>,

    /// Introduces randomization in network propagation of messages. This should only be set for
    /// testing purposes and will likely be removed in future versions.
    // TODO: Remove this functionality for mainnet
    pub propagation_percentage: Option<u8>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");

        // The default topics that we will initially subscribe to
        let topics = vec![
            GossipKind::BeaconBlock,
            GossipKind::BeaconAggregateAndProof,
            GossipKind::VoluntaryExit,
            GossipKind::ProposerSlashing,
            GossipKind::AttesterSlashing,
        ];

        // The function used to generate a gossipsub message id
        // We use base64(SHA256(data)) for content addressing
        let gossip_message_id = |message: &GossipsubMessage| {
            MessageId(base64::encode_config(
                &Sha256::digest(&message.data),
                base64::URL_SAFE_NO_PAD,
            ))
        };

        // gossipsub configuration
        // Note: The topics by default are sent as plain strings. Hashes are an optional
        // parameter.
        let gs_config = GossipsubConfigBuilder::new()
            .max_transmit_size(GOSSIP_MAX_SIZE)
            .heartbeat_interval(Duration::from_secs(1))
            .manual_propagation() // require validation before propagation
            .no_source_id()
            .message_id_fn(gossip_message_id)
            .build();

        // discv5 configuration
        let discv5_config = Discv5ConfigBuilder::new()
            .request_timeout(Duration::from_secs(4))
            .request_retries(2)
            .enr_update(true) // update IP based on PONG responses
            .enr_peer_update_min(2) // prevents NAT's should be raised for mainnet
            .query_parallelism(5)
            .query_timeout(Duration::from_secs(60))
            .query_peer_timeout(Duration::from_secs(2))
            .ip_limit(false) // limits /24 IP's in buckets. Enable for mainnet
            .ping_interval(Duration::from_secs(300))
            .build();

        // NOTE: Some of these get overridden by the corresponding CLI default values.
        Config {
            network_dir,
            listen_address: "0.0.0.0".parse().expect("valid ip address"),
            libp2p_port: 9000,
            discovery_port: 9000,
            enr_address: None,
            enr_udp_port: None,
            enr_tcp_port: None,
            max_peers: 50,
            secret_key_hex: None,
            gs_config,
            discv5_config,
            boot_nodes: vec![],
            libp2p_nodes: vec![],
            client_version: version::version(),
            topics,
            propagation_percentage: None,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Macros for generating protocol-related functions and structs.

/// A conveinence macro for generating `WireEnum`-implementing enums.
///
/// Syntax is as follows:
/// ```text
/// wire_enum! {
///     /// This is my enum.
///     pub enum MyEnum : u8 {
///         /// Variant `A`.
///         A = 0x00,
///         /// Variant `B`.
///         B = 0x01,
///     }
/// }
/// ```
/// This macro will generate an implementation of `WireEnum<Wire=u8>` for
/// the above enum.
macro_rules! wire_enum {
    ($(#[$meta:meta])* $vis:vis enum $name:ident : $wire:ident {
        $($(#[$meta_variant:meta])* $variant:ident = $value:literal,)*
    }) => {
        $(#[$meta])*
        #[repr($wire)]
        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
        $vis enum $name {
           $(
               $(#[$meta_variant])*
               $variant = $value,
           )*
        }

        impl $crate::protocol::WireEnum for $name {
            type Wire = $wire;
            fn to_wire(self) -> Self::Wire {
                self as $wire
            }
            fn from_wire(wire: Self::Wire) -> Option<Self> {
                match wire {
                    $(
                        $value => Some(Self::$variant),
                    )*
                    _ => None,
                }
            }
        }
    }
}

#[cfg(feature = "arbitrary-derive")]
/// Convenience trait for use with `make_fuzz_safe`.
#[doc(hidden)]
pub trait FuzzSafe {
    type Safe: libfuzzer_sys::arbitrary::Arbitrary;
}

/// Convenience macro for generating a "fuzz-safe" version of the struct that
/// can be cheaply converted into the original struct.
macro_rules! make_fuzz_safe {
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident $(<$lt:lifetime>)? as $wrapper_name:ident {$(
            $(#[$field_meta:meta])*
            $field_vis:vis $field:ident:
                // Because we need to destructure on this, this *cannot* be a
                // type. Hence, we accept a token-tree instead, with the
                // understanding that callers will wrap complex types in
                // parentheses.
                //
                // This is a limitation of the macro engine. See
                // https://danielkeep.github.io/tlborm/book/mbe-min-captures-and-expansion-redux.html
            $field_ty:tt,
        )*}
    ) => {
        $(#[$meta])*
        #[allow(unused_parens)]
        $vis struct $name $(<$lt>)? {$(
            $(#[$field_meta])*
            $field_vis $field: $field_ty,
        )*}

        #[cfg(feature = "arbitrary-derive")]
        #[derive(Clone, Debug, Arbitrary)]
        #[allow(unused_parens)]
        #[doc(hidden)]
        $vis struct $wrapper_name {$(
            $field: make_fuzz_safe!(@convert_ty, $field_ty),
        )*}
        #[cfg(feature = "arbitrary-derive")]
        impl $wrapper_name {
            /// Borrow this value into a protocol struct.
            pub fn as_ref<$($lt)?>(&$($lt)? self)
            -> $name<$($lt)?> {
                $name {$(
                    $field: make_fuzz_safe!(@extract_ty,
                                            self.$field: $field_ty),
                )*}
            }
        }

        impl<$($lt)?> $crate::protocol::macros::FuzzSafe for $name<$($lt)?> {
            type Safe = $wrapper_name;
        }
    };
    (@convert_ty, (&$lt:tt [$ty:ty])) => {std::boxed::Box<[T]>};
    (@convert_ty, (&$lt:tt str)) => {std::boxed::Box<str>};
    (@convert_ty, (&$lt:tt $ty:ty)) => {$ty};
    (@convert_ty, $ty:ty) => {$ty};
    (@extract_ty, $s:tt.$f:tt: (&$lt:lifetime $ty:ty)) => {&$s.$f};
    (@extract_ty, $s:tt.$f:tt: $ty:ty) => {$s.$f};
}
<commit_msg>[protocol] Fix a build break when not building for fuzzing<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Macros for generating protocol-related functions and structs.

/// A conveinence macro for generating `WireEnum`-implementing enums.
///
/// Syntax is as follows:
/// ```text
/// wire_enum! {
///     /// This is my enum.
///     pub enum MyEnum : u8 {
///         /// Variant `A`.
///         A = 0x00,
///         /// Variant `B`.
///         B = 0x01,
///     }
/// }
/// ```
/// This macro will generate an implementation of `WireEnum<Wire=u8>` for
/// the above enum.
macro_rules! wire_enum {
    ($(#[$meta:meta])* $vis:vis enum $name:ident : $wire:ident {
        $($(#[$meta_variant:meta])* $variant:ident = $value:literal,)*
    }) => {
        $(#[$meta])*
        #[repr($wire)]
        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
        $vis enum $name {
           $(
               $(#[$meta_variant])*
               $variant = $value,
           )*
        }

        impl $crate::protocol::WireEnum for $name {
            type Wire = $wire;
            fn to_wire(self) -> Self::Wire {
                self as $wire
            }
            fn from_wire(wire: Self::Wire) -> Option<Self> {
                match wire {
                    $(
                        $value => Some(Self::$variant),
                    )*
                    _ => None,
                }
            }
        }
    }
}

#[cfg(feature = "arbitrary-derive")]
/// Convenience trait for use with `make_fuzz_safe`.
#[doc(hidden)]
pub trait FuzzSafe {
    type Safe: libfuzzer_sys::arbitrary::Arbitrary;
}

/// Convenience macro for generating a "fuzz-safe" version of the struct that
/// can be cheaply converted into the original struct.
macro_rules! make_fuzz_safe {
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident $(<$lt:lifetime>)? as $wrapper_name:ident {$(
            $(#[$field_meta:meta])*
            $field_vis:vis $field:ident:
                // Because we need to destructure on this, this *cannot* be a
                // type. Hence, we accept a token-tree instead, with the
                // understanding that callers will wrap complex types in
                // parentheses.
                //
                // This is a limitation of the macro engine. See
                // https://danielkeep.github.io/tlborm/book/mbe-min-captures-and-expansion-redux.html
            $field_ty:tt,
        )*}
    ) => {
        $(#[$meta])*
        #[allow(unused_parens)]
        $vis struct $name $(<$lt>)? {$(
            $(#[$field_meta])*
            $field_vis $field: $field_ty,
        )*}

        #[cfg(feature = "arbitrary-derive")]
        #[derive(Clone, Debug, Arbitrary)]
        #[allow(unused_parens)]
        #[doc(hidden)]
        $vis struct $wrapper_name {$(
            $field: make_fuzz_safe!(@convert_ty, $field_ty),
        )*}
        #[cfg(feature = "arbitrary-derive")]
        impl $wrapper_name {
            /// Borrow this value into a protocol struct.
            pub fn as_ref<$($lt)?>(&$($lt)? self)
            -> $name<$($lt)?> {
                $name {$(
                    $field: make_fuzz_safe!(@extract_ty,
                                            self.$field: $field_ty),
                )*}
            }
        }
        #[cfg(feature = "arbitrary-derive")]
        impl<$($lt)?> $crate::protocol::macros::FuzzSafe for $name<$($lt)?> {
            type Safe = $wrapper_name;
        }
    };
    (@convert_ty, (&$lt:tt [$ty:ty])) => {std::boxed::Box<[$ty]>};
    (@convert_ty, (&$lt:tt str)) => {std::boxed::Box<str>};
    (@convert_ty, (&$lt:tt $ty:ty)) => {$ty};
    (@convert_ty, $ty:ty) => {$ty};
    (@extract_ty, $s:tt.$f:tt: (&$lt:lifetime $ty:ty)) => {&$s.$f};
    (@extract_ty, $s:tt.$f:tt: $ty:ty) => {$s.$f};
}
<|endoftext|>


<commit_before>use num::{PrimInt, Signed};
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// Otherwise, to avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed> (coefficients: &mut [T], input: T)->Result <(),()> {
  if coefficients.len() <= 1 {return Ok(());}
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() <= 1 {return true;}
  let mut factor = T::one();
  let input = input.abs();
  let global_maximum = T::max_value() >> (coefficients.len() - 1) ;
  for (index, coefficient) in coefficients.iter().enumerate() {
    let maximum = min (global_maximum, maximum (index));
    if coefficient == &T::min_value() {return false;}
    match coefficient.abs().checked_mul (&factor) {
      None => return false,
      Some (term) => if term > maximum {return false;},
    }
    if index + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Anything in the range [-result, result] is safe to translate to; anything outside isn't.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->Option <T> {
  if coefficients.len() <= 1 || coefficients [1..].iter().all (| coefficient | coefficient == &T::zero()) {return Some (T::max_value())}
  // if we know that there's at least one nonzero non-constant coefficient, T::max_value is never legal, so we can pick a min that definitely legal and a max that's definitely not
  let mut min = -T::one();
  let mut max = T::max_value();
  while min + T::one() < max {
    let mid = (min >> 1) + (max >> 1) + (min & max & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid;
    }
  }
  if min < T::zero() {None}
  else {Some (min)}
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Anything in the range [-result, result] is safe to translate to.
/// Anything outside the range (-result*2, result*2) isn't.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: &mut [T], maximum: MaximumFn)->Option <T> {
  if coefficients.len() <= 1 {return Some (T::max_value())}
  let global_maximum = T::max_value() >> (coefficients.len() - 1) ;
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    let maximum = min (global_maximum, maximum (power));
    while magnitude > (maximum >> (result_shift*power)) {
      if result_shift == 0 {return None;}
      result_shift -= 1;
    }
  }
  Some (T::one() << result_shift)
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }
}
<commit_msg>Fixed a constraint on input size for safe translation<commit_after>use num::{PrimInt, Signed};
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// Otherwise, to avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed> (coefficients: &mut [T], input: T)->Result <(),()> {
  if coefficients.len() <= 1 {return Ok(());}
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() <= 1 {return true;}
  let mut factor = T::one();
  let input = input.abs();
  let sum_safety_shift = coefficients.len() - 1;
  let mut running_maximum = T::max_value();
  for (power, coefficient) in coefficients.iter().enumerate() {
    running_maximum = min (running_maximum, maximum (power) >> sum_safety_shift);
    if coefficient == &T::min_value() {return false;}
    match coefficient.abs().checked_mul (&factor) {
      None => return false,
      Some (term) => if term > running_maximum {return false;},
    }
    if power + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Anything in the range [-result, result] is safe to translate to; anything outside isn't.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->Option <T> {
  if coefficients.len() <= 1 || coefficients [1..].iter().all (| coefficient | coefficient == &T::zero()) {return Some (T::max_value())}
  // if we know that there's at least one nonzero non-constant coefficient, T::max_value is never legal, so we can pick a min that definitely legal and a max that's definitely not
  let mut min = -T::one();
  let mut max = T::max_value();
  while min + T::one() < max {
    let mid = (min >> 1) + (max >> 1) + (min & max & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid;
    }
  }
  if min < T::zero() {None}
  else {Some (min)}
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Anything in the range [-result, result] is safe to translate to.
/// Anything outside the range (-result*2, result*2) isn't.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed, MaximumFn: Fn (usize)->T> (coefficients: &mut [T], maximum: MaximumFn)->Option <T> {
  if coefficients.len() <= 1 {return Some (T::max_value())}
  let sum_safety_shift = coefficients.len() - 1;
  let mut running_maximum = T::max_value();
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    running_maximum = min (running_maximum, maximum (power) >> sum_safety_shift);
    while magnitude > (running_maximum >> (result_shift*power)) {
      if result_shift == 0 {return None;}
      result_shift -= 1;
    }
  }
  Some (T::one() << result_shift)
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::fmt::Debug;
use std::borrow::Borrow;
use std::marker::PhantomData;

use perlin_core::index::posting::{Posting, PostingIterator};
use perlin_core::utils::seeking_iterator::{PeekableSeekable, SeekingIterator};
use perlin_core::utils::progress::Progress;
use perlin_core::index::Index;

use language::CanApply;
use query::{ToOperands, Operand, Operator, ChainingOperator};

/// Mimics the functionality of the `try!` macro for `Option`s.
/// Evaluates `Some(x)` to x. Else it returns `None`.
macro_rules! try_option{
    ($operand:expr) => {
        if let Some(x) = $operand {
            x
        } else {
            return None;
        }
    }
}

#[derive(Debug)]
pub enum Combinator {
    All,
    Any,
}

pub struct SplitFunnel<'a, T: 'a + Hash + Eq, CB> {
    index: &'a Index<T>,
    combinator: Combinator,
    chaining_operator: ChainingOperator,
    result: Vec<PeekableSeekable<Operand<'a>>>,
    callback: CB,
}

impl<'a, T: 'a + Hash + Eq, CB> SplitFunnel<'a, T, CB> {
    pub fn create(chaining_operator: ChainingOperator,
                  combinator: Combinator,
                  index: &'a Index<T>,
                  cb: CB)
                  -> Self {
        SplitFunnel {
            index: index,
            combinator: combinator,
            chaining_operator: chaining_operator,
            callback: cb,
            result: Vec::new(),
        }
    }
}

impl<'a, T: 'a + Hash + Eq + Ord, CB> CanApply<T> for SplitFunnel<'a, T, CB>
    where CB: CanApply<T>
{
    type Output = CB::Output;

    fn apply(&mut self, term: T) {
        // Query index
        match self.index.query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
        // And keep going
        self.callback.apply(term);
    }
}

impl<'a, T: 'a + Hash + Eq, CB> ToOperands<'a> for SplitFunnel<'a, T, CB>
    where CB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        let mut other = self.callback.to_operands();
        match self.combinator {
            Combinator::All => {
                other.push((self.chaining_operator,
                            PeekableSeekable::new(Operand::Operated(Box::new(And {}), self.result))))
            }
            Combinator::Any => {
                other.push((self.chaining_operator,
                            PeekableSeekable::new(Operand::Operated(Box::new(Or {}), self.result))))
            }
        }
        other
    }
}

/// This funnel is used at an end of a query pipeline
/// It calls `index.query_atom` and stores the result, which is lazy
/// When `to_operand` is then called, it packs everything into an operator!
// TODO: In this struct lies an opportunity to optimize
// If the operator is AND and one term returns an empty posting iterator
// We could skip the rest
// If the operator is Or and one term returns an empty posting iterator we
// could discard it
pub struct Funnel<'a, T:'a, TIndex: 'a> {
    index: &'a TIndex,
    combinator: Combinator,
    chaining_operator: ChainingOperator,
    result: Vec<PeekableSeekable<Operand<'a>>>,
    _term: PhantomData<T>
}

impl<'a, T: 'a, TIndex: 'a> Funnel<'a, T, TIndex> {
    pub fn create(chaining_operator: ChainingOperator,
                  combinator: Combinator,
                  index: &'a TIndex)
                  -> Self {
        Funnel {
            index: index,
            combinator: combinator,
            chaining_operator: chaining_operator,
            result: Vec::new(),
            _term: PhantomData,
        }
    }
}

impl<'a: 'b, 'b, T: 'a + Hash + Eq + Ord + Debug, TIndex> CanApply<&'b T> for Funnel<'a, T, TIndex>
    where TIndex: Borrow<Index<T>>
{
    type Output = T;

    fn apply(&mut self, term: &'b T) {
        match (self.index.borrow()).query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
    }
}

impl<'a, T: 'a + Hash + Eq + Ord + Debug, TIndex> CanApply<T> for Funnel<'a, T, TIndex>
    where TIndex: Borrow<Index<T>>
{
    type Output = T;

    fn apply(&mut self, term: T) {
        match (self.index.borrow()).query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
    }
}

impl<'a, T:'a,  TIndex> ToOperands<'a> for Funnel<'a, T, TIndex> {
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        if self.result.is_empty() {
            return vec![];
        }
        match self.combinator {
            Combinator::All => {
                vec![(self.chaining_operator,
                      PeekableSeekable::new(Operand::Operated(Box::new(And {}), self.result)))]
            }
            Combinator::Any => {
                vec![(self.chaining_operator,
                      PeekableSeekable::new(Operand::Operated(Box::new(Or {}), self.result)))]
            }
        }

    }
}
/// END FUNNEL

#[derive(Debug, Copy, Clone)]
pub struct And;

impl Operator for And {
    fn next(&mut self, operands: &mut [PeekableSeekable<Operand>]) -> Option<Posting> {
        let mut focus = try_option!(operands[0].next()); // Acts as temporary to be compared against
        let mut last_iter = 0; // The iterator that last set 'focus'
        'possible_documents: loop {
            // For every term
            for (i, input) in operands.iter_mut().enumerate() {
                // If the focus was set by the current iterator, we have a match
                // We cycled through all the iterators once
                if last_iter == i {
                    continue;
                }

                let v = try_option!(input.next_seek(&focus));
                if v.0 > focus.0 {
                    // If it is larger, we are now looking at a different focus.
                    // Reset focus and last_iter. Then start from the beginning
                    focus = v;
                    last_iter = i;
                    continue 'possible_documents;
                }
            }
            return Some(focus);
        }
    }

    fn next_seek(&mut self,
                 operands: &mut [PeekableSeekable<Operand>],
                 target: &Posting)
                 -> Option<Posting> {
       //Advance operands to `target`
        for op in operands.iter_mut() {
            op.peek_seek(target);
        }
        self.next(operands)
    }

    fn progress(&self,
                operands: &[PeekableSeekable<Operand>]) -> Progress {
        operands.iter().map(|op| op.inner().progress()).max().unwrap_or(Progress::done())
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Or;

impl Operator for Or {
    fn next(&mut self, operands: &mut [PeekableSeekable<Operand>]) -> Option<Posting> {
        // TODO: Probably improveable
        // Find the smallest current value of all operands
        let min_doc_id = operands.iter_mut()
            .map(|op| op.peek())
            .filter(|val| val.is_some())
            .map(|val| val.unwrap().doc_id())
            .min();

        // Walk over all operands. Advance those who emit the min value
        if min_doc_id.is_some() {
            let mut i = 0;
            let mut tmp = None;
            while i < operands.len() {
                let v = operands[i].peek().map(|p| p.doc_id());
                if !v.is_none() && v == min_doc_id {
                    tmp = operands[i].next();
                }
                i += 1;
            }
            tmp
        } else {
            None
        }
    }

    fn next_seek(&mut self,
                 operands: &mut [PeekableSeekable<Operand>],
                 target: &Posting)
                 -> Option<Posting> {
        //Advance operands to `target`
        for op in operands.iter_mut() {
            op.peek_seek(target);
        }
        self.next(operands)
    }

    fn progress(&self,
                operands: &[PeekableSeekable<Operand>]) -> Progress {
        operands.iter().map(|op| op.inner().progress()).min().unwrap_or(Progress::done())
    }
}
<commit_msg>allow querying fields<commit_after>use std::hash::Hash;
use std::fmt::Debug;
use std::borrow::Borrow;
use std::marker::PhantomData;

use perlin_core::index::posting::{Posting, PostingIterator};
use perlin_core::utils::seeking_iterator::{PeekableSeekable, SeekingIterator};
use perlin_core::utils::progress::Progress;
use perlin_core::index::Index;

use language::CanApply;
use query::{ToOperands, Operand, Operator, ChainingOperator};
use field::Fields;

/// Mimics the functionality of the `try!` macro for `Option`s.
/// Evaluates `Some(x)` to x. Else it returns `None`.
macro_rules! try_option{
    ($operand:expr) => {
        if let Some(x) = $operand {
            x
        } else {
            return None;
        }
    }
}

#[derive(Debug)]
pub enum Combinator {
    All,
    Any,
}

pub struct SplitFunnel<'a, T: 'a + Hash + Eq, CB> {
    index: &'a Index<T>,
    combinator: Combinator,
    chaining_operator: ChainingOperator,
    result: Vec<PeekableSeekable<Operand<'a>>>,
    callback: CB,
}

impl<'a, T: 'a + Hash + Eq, CB> SplitFunnel<'a, T, CB> {
    pub fn create(chaining_operator: ChainingOperator,
                  combinator: Combinator,
                  index: &'a Index<T>,
                  cb: CB)
                  -> Self {
        SplitFunnel {
            index: index,
            combinator: combinator,
            chaining_operator: chaining_operator,
            callback: cb,
            result: Vec::new(),
        }
    }
}

impl<'a, T: 'a + Hash + Eq + Ord, CB> CanApply<T> for SplitFunnel<'a, T, CB>
    where CB: CanApply<T>
{
    type Output = CB::Output;

    fn apply(&mut self, term: T) {
        // Query index
        match self.index.query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
        // And keep going
        self.callback.apply(term);
    }
}

impl<'a, T: 'a + Hash + Eq, CB> ToOperands<'a> for SplitFunnel<'a, T, CB>
    where CB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        let mut other = self.callback.to_operands();
        match self.combinator {
            Combinator::All => {
                other.push((self.chaining_operator,
                            PeekableSeekable::new(Operand::Operated(Box::new(And {}),
                                                                    self.result))))
            }
            Combinator::Any => {
                other.push((self.chaining_operator,
                            PeekableSeekable::new(Operand::Operated(Box::new(Or {}), self.result))))
            }
        }
        other
    }
}

/// This funnel is used at an end of a query pipeline
/// It calls `index.query_atom` and stores the result, which is lazy
/// When `to_operand` is then called, it packs everything into an operator!
// TODO: In this struct lies an opportunity to optimize
// If the operator is AND and one term returns an empty posting iterator
// We could skip the rest
// If the operator is Or and one term returns an empty posting iterator we
// could discard it
pub struct Funnel<'a, T: 'a, TIndex: 'a> {
    index: &'a TIndex,
    combinator: Combinator,
    chaining_operator: ChainingOperator,
    result: Vec<PeekableSeekable<Operand<'a>>>,
    _term: PhantomData<T>,
}

impl<'a, T: 'a, TIndex: 'a> Funnel<'a, T, TIndex> {
    pub fn create(chaining_operator: ChainingOperator,
                  combinator: Combinator,
                  index: &'a TIndex)
                  -> Self {
        Funnel {
            index: index,
            combinator: combinator,
            chaining_operator: chaining_operator,
            result: Vec::new(),
            _term: PhantomData,
        }
    }
}

impl<'a: 'b, 'b, T: 'a + Hash + Eq + Ord + Debug> CanApply<&'b T>
    for Funnel<'a, T, Fields<T>> {
    type Output = T;

    fn apply(&mut self, term: &'b T) {
        for index in self.index.fields.values() {
            match index.query_atom(&term) {
                PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
                PostingIterator::Decoder(decoder) => {
                    self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
                }
            }
        }
    }
}

impl<'a, T: 'a + Hash + Eq + Ord + Debug> CanApply<T>
    for Funnel<'a, T, Fields<T>> {
    type Output = T;

    fn apply(&mut self, term: T) {
        for index in self.index.fields.values() {
            match index.query_atom(&term) {
                PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
                PostingIterator::Decoder(decoder) => {
                    self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
                }
            }
        }
    }
}

impl<'a: 'b, 'b, T: 'a + Hash + Eq + Ord + Debug, TIndex> CanApply<&'b T> for Funnel<'a, T, TIndex>
    where TIndex: Borrow<Index<T>>
{
    type Output = T;

    fn apply(&mut self, term: &'b T) {
        match (self.index.borrow()).query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
    }
}

impl<'a, T: 'a + Hash + Eq + Ord + Debug, TIndex> CanApply<T> for Funnel<'a, T, TIndex>
    where TIndex: Borrow<Index<T>>
{
    type Output = T;

    fn apply(&mut self, term: T) {
        match (self.index.borrow()).query_atom(&term) {
            PostingIterator::Empty => self.result.push(PeekableSeekable::new(Operand::Empty)),
            PostingIterator::Decoder(decoder) => {
                self.result.push(PeekableSeekable::new(Operand::Term(decoder)))
            }
        }
    }
}

impl<'a, T: 'a, TIndex> ToOperands<'a> for Funnel<'a, T, TIndex> {
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        if self.result.is_empty() {
            return vec![];
        }
        match self.combinator {
            Combinator::All => {
                vec![(self.chaining_operator,
                      PeekableSeekable::new(Operand::Operated(Box::new(And {}), self.result)))]
            }
            Combinator::Any => {
                vec![(self.chaining_operator,
                      PeekableSeekable::new(Operand::Operated(Box::new(Or {}), self.result)))]
            }
        }

    }
}
/// END FUNNEL
#[derive(Debug, Copy, Clone)]
pub struct And;

impl Operator for And {
    fn next(&mut self, operands: &mut [PeekableSeekable<Operand>]) -> Option<Posting> {
        let mut focus = try_option!(operands[0].next()); // Acts as temporary to be compared against
        let mut last_iter = 0; // The iterator that last set 'focus'
        'possible_documents: loop {
            // For every term
            for (i, input) in operands.iter_mut().enumerate() {
                // If the focus was set by the current iterator, we have a match
                // We cycled through all the iterators once
                if last_iter == i {
                    continue;
                }

                let v = try_option!(input.next_seek(&focus));
                if v.0 > focus.0 {
                    // If it is larger, we are now looking at a different focus.
                    // Reset focus and last_iter. Then start from the beginning
                    focus = v;
                    last_iter = i;
                    continue 'possible_documents;
                }
            }
            return Some(focus);
        }
    }

    fn next_seek(&mut self,
                 operands: &mut [PeekableSeekable<Operand>],
                 target: &Posting)
                 -> Option<Posting> {
        // Advance operands to `target`
        for op in operands.iter_mut() {
            op.peek_seek(target);
        }
        self.next(operands)
    }

    fn progress(&self, operands: &[PeekableSeekable<Operand>]) -> Progress {
        operands.iter()
            .map(|op| op.inner().progress())
            .max()
            .unwrap_or(Progress::done())
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Or;

impl Operator for Or {
    fn next(&mut self, operands: &mut [PeekableSeekable<Operand>]) -> Option<Posting> {
        // TODO: Probably improveable
        // Find the smallest current value of all operands
        let min_doc_id = operands.iter_mut()
            .map(|op| op.peek())
            .filter(|val| val.is_some())
            .map(|val| val.unwrap().doc_id())
            .min();

        // Walk over all operands. Advance those who emit the min value
        if min_doc_id.is_some() {
            let mut i = 0;
            let mut tmp = None;
            while i < operands.len() {
                let v = operands[i].peek().map(|p| p.doc_id());
                if !v.is_none() && v == min_doc_id {
                    tmp = operands[i].next();
                }
                i += 1;
            }
            tmp
        } else {
            None
        }
    }

    fn next_seek(&mut self,
                 operands: &mut [PeekableSeekable<Operand>],
                 target: &Posting)
                 -> Option<Posting> {
        // Advance operands to `target`
        for op in operands.iter_mut() {
            op.peek_seek(target);
        }
        self.next(operands)
    }

    fn progress(&self, operands: &[PeekableSeekable<Operand>]) -> Progress {
        operands.iter()
            .map(|op| op.inner().progress())
            .min()
            .unwrap_or(Progress::done())
    }
}
<|endoftext|>


<commit_before>use ram::cell::CellHeader;
use ram::chunk::Chunks;
use ram::tombstone::Tombstone;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

pub mod combine;
pub mod compact;

pub struct Cleaner {
    chunks: Arc<Chunks>,
    stopped: Arc<AtomicBool>,
    segments_compact_per_turn: usize,
    segments_combine_per_turn: usize,
}

// The two-level cleaner
impl Cleaner {
    pub fn new_and_start(chunks: Arc<Chunks>) -> Cleaner {
        debug!("Starting cleaner for {} chunks", chunks.list.len());
        let stop_tag = Arc::new(AtomicBool::new(false));
        let segments_compact_per_turn = chunks.list[0].segs.len() / 10 + 1;
        let segments_combine_per_turn = chunks.list[0].segs.len() / 20 + 2;
        let cleaner = Cleaner {
            chunks: chunks.clone(),
            stopped: stop_tag.clone(),
            segments_compact_per_turn,
            segments_combine_per_turn,
        };
        let stop_tag_ref_clone = stop_tag.clone();
        let checks_ref_clone = chunks.clone();
        thread::Builder::new()
            .name("Cleaner sweeper".into())
            .spawn(move || {
                while !stop_tag.load(Ordering::Relaxed) {
                    for chunk in &chunks.list {
                        chunk.apply_dead_entry();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
            });
        thread::Builder::new()
            .name("Cleaner main".into())
            .spawn(move || {
                while !stop_tag_ref_clone.load(Ordering::Relaxed) {
                    for chunk in &checks_ref_clone.list {
                        // have to put it right here for cleaners will clear the tombstone death counter
                        chunk.scan_tombstone_survival();
                        trace!("Cleaning chunk {}", chunk.id);
                        let mut cleaned_space: usize = 0;
                        {
                            // compact
                            let segments_for_compact = chunk.segs_for_compact_cleaner();
                            if !segments_for_compact.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to compact, overflow {}",
                                    chunk.id,
                                    segments_for_compact.len(),
                                    segments_compact_per_turn
                                );
                                cleaned_space += segments_for_compact
                                    .into_iter()
                                    .take(segments_compact_per_turn) // limit max segment to clean per turn
                                    .map(|segment| {
                                        compact::CompactCleaner::clean_segment(chunk, &segment)
                                    })
                                    .sum::<usize>();
                            }
                        }

                        {
                            // combine
                            let segments_candidates_for_combine: Vec<_> =
                                chunk.segs_for_combine_cleaner();
                            let segments_for_combine: Vec<_> = segments_candidates_for_combine
                                .into_iter()
                                .take(segments_combine_per_turn)
                                .collect();
                            if !segments_for_combine.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to combine, overflow {}",
                                    chunk.id,
                                    segments_for_combine.len(),
                                    segments_combine_per_turn
                                );
                                cleaned_space += combine::CombinedCleaner::combine_segments(
                                    chunk,
                                    &segments_for_combine,
                                );
                            }
                        }

                        chunk
                            .total_space
                            .fetch_sub(cleaned_space, Ordering::Relaxed);
                        chunk.check_and_archive_segments();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
                warn!("Cleaner main thread stopped");
            });
        return cleaner;
    }
}
<commit_msg>segment selection is not calculated by chunk segment count<commit_after>use ram::cell::CellHeader;
use ram::chunk::Chunks;
use ram::tombstone::Tombstone;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

pub mod combine;
pub mod compact;

pub struct Cleaner {
    chunks: Arc<Chunks>,
    stopped: Arc<AtomicBool>
}

// The two-level cleaner
impl Cleaner {
    pub fn new_and_start(chunks: Arc<Chunks>) -> Cleaner {
        debug!("Starting cleaner for {} chunks", chunks.list.len());
        let stop_tag = Arc::new(AtomicBool::new(false));
        let cleaner = Cleaner {
            chunks: chunks.clone(),
            stopped: stop_tag.clone()
        };
        let stop_tag_ref_clone = stop_tag.clone();
        let checks_ref_clone = chunks.clone();
        thread::Builder::new()
            .name("Cleaner sweeper".into())
            .spawn(move || {
                while !stop_tag.load(Ordering::Relaxed) {
                    for chunk in &chunks.list {
                        chunk.apply_dead_entry();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
            });
        thread::Builder::new()
            .name("Cleaner main".into())
            .spawn(move || {
                while !stop_tag_ref_clone.load(Ordering::Relaxed) {
                    for chunk in &checks_ref_clone.list {
                        let segments_compact_per_turn = chunk.segs.len() / 10 + 1;
                        let segments_combine_per_turn = chunk.segs.len() / 20 + 2;
                        // have to put it right here for cleaners will clear the tombstone death counter
                        chunk.scan_tombstone_survival();
                        trace!("Cleaning chunk {}", chunk.id);
                        let mut cleaned_space: usize = 0;
                        {
                            // compact
                            let segments_for_compact = chunk.segs_for_compact_cleaner();
                            if !segments_for_compact.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to compact, overflow {}",
                                    chunk.id,
                                    segments_for_compact.len(),
                                    segments_compact_per_turn
                                );
                                cleaned_space += segments_for_compact
                                    .into_iter()
                                    .take(segments_compact_per_turn) // limit max segment to clean per turn
                                    .map(|segment| {
                                        compact::CompactCleaner::clean_segment(chunk, &segment)
                                    })
                                    .sum::<usize>();
                            }
                        }

                        {
                            // combine
                            let segments_candidates_for_combine: Vec<_> =
                                chunk.segs_for_combine_cleaner();
                            let segments_for_combine: Vec<_> = segments_candidates_for_combine
                                .into_iter()
                                .take(segments_combine_per_turn)
                                .collect();
                            if !segments_for_combine.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to combine, overflow {}",
                                    chunk.id,
                                    segments_for_combine.len(),
                                    segments_combine_per_turn
                                );
                                cleaned_space += combine::CombinedCleaner::combine_segments(
                                    chunk,
                                    &segments_for_combine,
                                );
                            }
                        }

                        chunk
                            .total_space
                            .fetch_sub(cleaned_space, Ordering::Relaxed);
                        chunk.check_and_archive_segments();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
                warn!("Cleaner main thread stopped");
            });
        return cleaner;
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Neg, Rem};
use std::cmp::PartialEq;
use super::super::num::{Num, Zero, One, Signed};
use super::parse_decimal_error::ParseDecimalError;

const SIGN_MASK: u32 = 0b1_00000_000000_00000000000000000000;
const COMBINATION_MASK: u32 = 0b0_11111_000000_00000000000000000000;

/// Represents a 32-bit decimal number according to the IEEE 754-2008 standard.
///
/// Decimal32 supports 7 decimal digits of significand and an exponent range of −95 to +96, i.e.
/// ±0.000000×10^−95 to ±9.999999×10^96. (Equivalently, ±0000000×10^−101 to ±9999999×10^90.)
///
/// Read more [here](https://en.wikipedia.org/wiki/Decimal32_floating-point_format).
#[derive(Debug, Clone, Copy)]
pub struct Decimal32 {
    data: u32,
}

impl Decimal32 {
    /// Creates and initializes a Decimal32 representation of zero.
    pub fn new() -> Decimal32 {
        Decimal32::zero()
    }

    /// Creates and initialize a Decimal32 from its significant parts: the sign, exponent, and
    /// significand, respectively.
    ///
    /// Returns Err(String) if either the exponent or significand is out of range.
    pub fn from_data(is_negative: bool,
                     exponent: i32,
                     significand: u32)
                     -> Result<Decimal32, String> {
        if exponent < -101 {
            Err("Exponent cannot be less than -101.".to_string())
        } else if exponent > 90 {
            Err("Exponent cannot be greater than 90.".to_string())
        } else if significand > 10_485_759 {
            Err("Significand cannot be greater than 10,485,759.".to_string())
        } else {
            let sign_field = (if is_negative { 1 } else { 0 }) << 31;
            let stored_exponent = ((exponent + 101) as u32);

            let implicit_field;
            let exponent_field;
            let significand_field;
            if significand < 8_388_608 {
                implicit_field = 0;
                exponent_field = stored_exponent << 23; // TODO think
                significand_field = significand;
            } else {
                // 8,388,608 is the first number that requires the implicit (100) in the significand
                implicit_field = 0b11 << 29;
                exponent_field = stored_exponent << 21;
                // remove the implicit (100)
                significand_field = significand - 0b1000_0000_0000_0000_0000_0000;
            }
            let ok_result = Decimal32 {
                data: sign_field + implicit_field + exponent_field + significand_field
            };
            Ok(ok_result)
        }
    }

    /// Creates and initializes a Decimal32 representation of positive infinity.
    pub fn infinity() -> Decimal32 {
        Decimal32 { data: 0b0_11110_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 representation of negative infinity.
    pub fn neg_infinity() -> Decimal32 {
        Decimal32 { data: 0b1_11110_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a quiet NaN.
    pub fn quiet_nan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a quiet NaN.
    pub fn qnan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a signaling NaN.
    pub fn signaling_nan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_100000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a signaling NaN.
    pub fn snan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_100000_00000000000000000000 }
    }

    /// Copies the data passed into the data in the Decimal32.
    pub fn from_bin(data: u32) -> Decimal32 {
        Decimal32 { data: data }
    }

    /// Returns true if the combination field signifies infinity, and false otherwise.
    pub fn is_infinity(&self) -> bool {
        self.get_combination_field() == 0b11110
    }

    /// Returns true if the combination field signifies infinity and the sign is positive, and false
    /// otherwise.
    pub fn is_pos_infinity(&self) -> bool {
        self.is_positive() && self.is_infinity()
    }

    /// Returns true if the combination field signifies infinity and the sign is negative, and false
    /// otherwise.
    pub fn is_neg_infinity(&self) -> bool {
        self.is_negative() && self.is_infinity()
    }

    /// Returns true if the combination field signifies NaN, and false otherwise.
    pub fn is_nan(&self) -> bool {
        self.get_combination_field() == 0b11111
    }

    /// Returns the three defining pieces of the decimal - the sign (true if negative), the
    /// exponent, and the significand, respectively.
    ///
    /// Do not expect well-behaved results if this decimal is NaN or infinity.
    pub fn get_data(&self) -> (bool, i32, u32) {
        let sign = self.get_sign_field() != 0;
        let (exponent, significand) = if self.get_first_two_bits_combination_field() < 3 {
            ((self.get_normal_exponent() as i32) - 101, self.get_normal_significand())
        } else {
            // self.get_second_two_bits_combination_field() < 3
            ((self.get_shifted_exponent() as i32) - 101, self.get_shifted_significand())
        };
        (sign, exponent, significand)
    }

    pub fn get_exponent(&self) -> i32 {
        let exponent = if self.get_first_two_bits_combination_field() < 3 {
            self.get_normal_exponent()
        } else {
            // self.get_second_two_bits_combination_field() < 3
            self.get_shifted_exponent()
        };
        (exponent as i32) - 101
    }

    fn get_sign_field(&self) -> u32 {
        (self.data & SIGN_MASK) >> 31
    }

    fn get_combination_field(&self) -> u32 {
        (self.data & COMBINATION_MASK) >> 26
    }

    fn get_first_two_bits_combination_field(&self) -> u32 {
        let combination_field = self.get_combination_field();
        combination_field >> 3
    }

    fn get_second_two_bits_combination_field(&self) -> u32 {
        let mask = 0b00110;
        let combination_field = self.get_combination_field();
        (combination_field & mask) >> 1
    }

    fn get_normal_exponent(&self) -> u32 {
        let mask: u32 = 0b0_00111_111000_00000000000000000000;
        (self.data & mask) >> 23
    }

    fn get_shifted_exponent(&self) -> u32 {
        let mask: u32 = 0b0_00001_111110_00000000000000000000;
        (self.data & mask) >> 21
    }

    fn get_normal_significand(&self) -> u32 {
        let mask = 0b0_00000_000111_11111111111111111111;
        self.data & mask
    }

    fn get_shifted_significand(&self) -> u32 {
        let implicit_100 = 0b100_0_00000_00000_00000_00000;
        let mask = 0b0_00000_000001_11111111111111111111;
        implicit_100 + (self.data & mask)
    }

    fn shift_exponent(&self, factor: i32) -> Decimal32 {
        let (_, exponent, significand) = self.get_data();
        let shifted_exponent = exponent + factor;
        let shifted_significand = (significand as f64) * 10f64.powi(-factor);
        unimplemented!()
    }
}

impl Add<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn add(self, other: Decimal32) -> Decimal32 {
        let sign = self.get_sign_field();

        if self.is_nan() || other.is_nan() {
            // if either operand is NaN, so is the result
            Decimal32::qnan()
        } else if self.is_infinity() {
            if self.is_positive() {
                if other.is_neg_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is positive infinity, and the other is not negative
                    // infinity or NaN, the result is positive infinity
                    Decimal32::infinity()
                }
            } else {
                if other.is_pos_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is negative infinity, and the other is not positive
                    // infinity or NaN, the result is negative infinity
                    Decimal32::neg_infinity()
                }
            }
        } else if other.is_infinity() {
            if other.is_positive() {
                if self.is_neg_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is positive infinity, and the other is not negative
                    // infinity or NaN, the result is positive infinity
                    Decimal32::infinity()
                }
            } else {
                if self.is_pos_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is negative infinity, and the other is not positive
                    // infinity or NaN, the result is negative infinity
                    Decimal32::neg_infinity()
                }
            }
        } else {
            let exponent;
            let significand;
            if self.get_first_two_bits_combination_field() < 3 {
                exponent = self.get_normal_exponent();
                significand = self.get_normal_significand();
            } else {
                // self.get_second_two_bits_combination_field() < 3
                exponent = self.get_shifted_exponent();
                significand = self.get_shifted_significand();
            }
            unimplemented!() // TODO
        }
    }
}

impl Sub<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn sub(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Mul<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn mul(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Div<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn div(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Neg for Decimal32 {
    type Output = Decimal32;

    fn neg(self) -> Decimal32 {
        Decimal32 { data: self.data ^ 1 << 31 }
    }
}

impl Rem<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn rem(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl PartialEq for Decimal32 {
    fn eq(&self, other: &Decimal32) -> bool {
        true // TODO
    }
}

impl Num for Decimal32 {
    type FromStrRadixErr = ParseDecimalError;

    fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
        Ok(Decimal32::zero()) // TODO
    }
}

impl Zero for Decimal32 {
    fn zero() -> Decimal32 {
        Decimal32 { data: 0b0_00000_000000_00000000000000000000 }
    }

    fn is_zero(&self) -> bool {
        true
    }
}

impl One for Decimal32 {
    fn one() -> Decimal32 {
        Decimal32 { data: 0b0_00000_000000_00000000000000000001 }
    }
}

impl Signed for Decimal32 {
    fn abs(&self) -> Decimal32 {
        Decimal32 { data: self.data & (!SIGN_MASK) }
    }

    fn abs_sub(&self, other: &Decimal32) -> Decimal32 {
        // TODO
        // The positive difference of two numbers.
        // Returns zero if the number is less than or equal to other, otherwise the difference between self and other is returned.
        *self
    }

    fn signum(&self) -> Decimal32 {
        // TODO
        // Returns the sign of the number.
        // For f32 and f64:
        // 1.0 if the number is positive, +0.0 or INFINITY
        // -1.0 if the number is negative, -0.0 or NEG_INFINITY
        // NaN if the number is NaN
        *self
    }

    /// Note: Zero can be positive or negative.
    fn is_positive(&self) -> bool {
        self.get_sign_field() == 0
    }

    /// Note: Zero can be positive or negative.
    fn is_negative(&self) -> bool {
        self.get_sign_field() != 0
    }
}
    <commit_msg>removed unnecessary parens in from_data()<commit_after>use std::ops::{Add, Sub, Mul, Div, Neg, Rem};
use std::cmp::PartialEq;
use super::super::num::{Num, Zero, One, Signed};
use super::parse_decimal_error::ParseDecimalError;

const SIGN_MASK: u32 = 0b1_00000_000000_00000000000000000000;
const COMBINATION_MASK: u32 = 0b0_11111_000000_00000000000000000000;

/// Represents a 32-bit decimal number according to the [IEEE 754-2008 standard]
/// (https://en.wikipedia.org/wiki/Decimal32_floating-point_format).
///
/// Decimal32 supports 7 decimal digits of significand and an exponent range of −95 to +96, i.e.
/// ±0.000000×10^−95 to ±9.999999×10^96. (Equivalently, ±0000000×10^−101 to ±9999999×10^90.)
#[derive(Debug, Clone, Copy)]
pub struct Decimal32 {
    data: u32,
}

impl Decimal32 {
    /// Creates and initializes a Decimal32 representation of zero.
    pub fn new() -> Decimal32 {
        Decimal32::zero()
    }

    /// Creates and initialize a Decimal32 from its significant parts: the sign, exponent, and
    /// significand, respectively.
    ///
    /// Returns Err(String) if either the exponent or significand is out of range.
    pub fn from_data(is_negative: bool,
                     exponent: i32,
                     significand: u32)
                     -> Result<Decimal32, String> {
        if exponent < -101 {
            Err("Exponent cannot be less than -101.".to_string())
        } else if exponent > 90 {
            Err("Exponent cannot be greater than 90.".to_string())
        } else if significand > 10_485_759 {
            Err("Significand cannot be greater than 10,485,759.".to_string())
        } else {
            let sign_field = (if is_negative { 1 } else { 0 }) << 31;
            let stored_exponent = (exponent + 101) as u32;

            let implicit_field;
            let exponent_field;
            let significand_field;
            if significand < 8_388_608 {
                implicit_field = 0;
                exponent_field = stored_exponent << 23; // TODO think
                significand_field = significand;
            } else {
                // 8,388,608 is the first number that requires the implicit (100) in the significand
                implicit_field = 0b11 << 29;
                exponent_field = stored_exponent << 21;
                // remove the implicit (100)
                significand_field = significand - 0b1000_0000_0000_0000_0000_0000;
            }
            let ok_result = Decimal32 {
                data: sign_field + implicit_field + exponent_field + significand_field
            };
            Ok(ok_result)
        }
    }

    /// Creates and initializes a Decimal32 representation of positive infinity.
    pub fn infinity() -> Decimal32 {
        Decimal32 { data: 0b0_11110_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 representation of negative infinity.
    pub fn neg_infinity() -> Decimal32 {
        Decimal32 { data: 0b1_11110_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a quiet NaN.
    pub fn quiet_nan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a quiet NaN.
    pub fn qnan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_000000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a signaling NaN.
    pub fn signaling_nan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_100000_00000000000000000000 }
    }

    /// Creates and initializes a Decimal32 that is specially encoded as a signaling NaN.
    pub fn snan() -> Decimal32 {
        Decimal32 { data: 0b0_11111_100000_00000000000000000000 }
    }

    /// Copies the data passed into the data in the Decimal32.
    pub fn from_bin(data: u32) -> Decimal32 {
        Decimal32 { data: data }
    }

    /// Returns true if the combination field signifies infinity, and false otherwise.
    pub fn is_infinity(&self) -> bool {
        self.get_combination_field() == 0b11110
    }

    /// Returns true if the combination field signifies infinity and the sign is positive, and false
    /// otherwise.
    pub fn is_pos_infinity(&self) -> bool {
        self.is_positive() && self.is_infinity()
    }

    /// Returns true if the combination field signifies infinity and the sign is negative, and false
    /// otherwise.
    pub fn is_neg_infinity(&self) -> bool {
        self.is_negative() && self.is_infinity()
    }

    /// Returns true if the combination field signifies NaN, and false otherwise.
    pub fn is_nan(&self) -> bool {
        self.get_combination_field() == 0b11111
    }

    /// Returns the three defining pieces of the decimal - the sign (true if negative), the
    /// exponent, and the significand, respectively.
    ///
    /// Do not expect well-behaved results if this decimal is NaN or infinity.
    pub fn get_data(&self) -> (bool, i32, u32) {
        let sign = self.get_sign_field() != 0;
        let (exponent, significand) = if self.get_first_two_bits_combination_field() < 3 {
            ((self.get_normal_exponent() as i32) - 101, self.get_normal_significand())
        } else {
            // self.get_second_two_bits_combination_field() < 3
            ((self.get_shifted_exponent() as i32) - 101, self.get_shifted_significand())
        };
        (sign, exponent, significand)
    }

    pub fn get_exponent(&self) -> i32 {
        let exponent = if self.get_first_two_bits_combination_field() < 3 {
            self.get_normal_exponent()
        } else {
            // self.get_second_two_bits_combination_field() < 3
            self.get_shifted_exponent()
        };
        (exponent as i32) - 101
    }

    fn get_sign_field(&self) -> u32 {
        (self.data & SIGN_MASK) >> 31
    }

    fn get_combination_field(&self) -> u32 {
        (self.data & COMBINATION_MASK) >> 26
    }

    fn get_first_two_bits_combination_field(&self) -> u32 {
        let combination_field = self.get_combination_field();
        combination_field >> 3
    }

    fn get_second_two_bits_combination_field(&self) -> u32 {
        let mask = 0b00110;
        let combination_field = self.get_combination_field();
        (combination_field & mask) >> 1
    }

    fn get_normal_exponent(&self) -> u32 {
        let mask: u32 = 0b0_00111_111000_00000000000000000000;
        (self.data & mask) >> 23
    }

    fn get_shifted_exponent(&self) -> u32 {
        let mask: u32 = 0b0_00001_111110_00000000000000000000;
        (self.data & mask) >> 21
    }

    fn get_normal_significand(&self) -> u32 {
        let mask = 0b0_00000_000111_11111111111111111111;
        self.data & mask
    }

    fn get_shifted_significand(&self) -> u32 {
        let implicit_100 = 0b100_0_00000_00000_00000_00000;
        let mask = 0b0_00000_000001_11111111111111111111;
        implicit_100 + (self.data & mask)
    }

    fn shift_exponent(&self, factor: i32) -> Decimal32 {
        let (_, exponent, significand) = self.get_data();
        let shifted_exponent = exponent + factor;
        let shifted_significand = (significand as f64) * 10f64.powi(-factor);
        unimplemented!()
    }
}

impl Add<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn add(self, other: Decimal32) -> Decimal32 {
        let sign = self.get_sign_field();

        if self.is_nan() || other.is_nan() {
            // if either operand is NaN, so is the result
            Decimal32::qnan()
        } else if self.is_infinity() {
            if self.is_positive() {
                if other.is_neg_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is positive infinity, and the other is not negative
                    // infinity or NaN, the result is positive infinity
                    Decimal32::infinity()
                }
            } else {
                if other.is_pos_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is negative infinity, and the other is not positive
                    // infinity or NaN, the result is negative infinity
                    Decimal32::neg_infinity()
                }
            }
        } else if other.is_infinity() {
            if other.is_positive() {
                if self.is_neg_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is positive infinity, and the other is not negative
                    // infinity or NaN, the result is positive infinity
                    Decimal32::infinity()
                }
            } else {
                if self.is_pos_infinity() {
                    // if the operands are opposing infinities, the result is sNaN
                    Decimal32::snan()
                } else {
                    // if the left operand is negative infinity, and the other is not positive
                    // infinity or NaN, the result is negative infinity
                    Decimal32::neg_infinity()
                }
            }
        } else {
            let exponent;
            let significand;
            if self.get_first_two_bits_combination_field() < 3 {
                exponent = self.get_normal_exponent();
                significand = self.get_normal_significand();
            } else {
                // self.get_second_two_bits_combination_field() < 3
                exponent = self.get_shifted_exponent();
                significand = self.get_shifted_significand();
            }
            unimplemented!() // TODO
        }
    }
}

impl Sub<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn sub(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Mul<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn mul(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Div<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn div(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl Neg for Decimal32 {
    type Output = Decimal32;

    fn neg(self) -> Decimal32 {
        Decimal32 { data: self.data ^ 1 << 31 }
    }
}

impl Rem<Decimal32> for Decimal32 {
    type Output = Decimal32;

    fn rem(self, other: Decimal32) -> Decimal32 {
        self // TODO
    }
}

impl PartialEq for Decimal32 {
    fn eq(&self, other: &Decimal32) -> bool {
        true // TODO
    }
}

impl Num for Decimal32 {
    type FromStrRadixErr = ParseDecimalError;

    fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
        Ok(Decimal32::zero()) // TODO
    }
}

impl Zero for Decimal32 {
    fn zero() -> Decimal32 {
        Decimal32 { data: 0b0_00000_000000_00000000000000000000 }
    }

    fn is_zero(&self) -> bool {
        true
    }
}

impl One for Decimal32 {
    fn one() -> Decimal32 {
        Decimal32 { data: 0b0_00000_000000_00000000000000000001 }
    }
}

impl Signed for Decimal32 {
    fn abs(&self) -> Decimal32 {
        Decimal32 { data: self.data & (!SIGN_MASK) }
    }

    fn abs_sub(&self, other: &Decimal32) -> Decimal32 {
        // TODO
        // The positive difference of two numbers.
        // Returns zero if the number is less than or equal to other, otherwise the difference between self and other is returned.
        *self
    }

    fn signum(&self) -> Decimal32 {
        // TODO
        // Returns the sign of the number.
        // For f32 and f64:
        // 1.0 if the number is positive, +0.0 or INFINITY
        // -1.0 if the number is negative, -0.0 or NEG_INFINITY
        // NaN if the number is NaN
        *self
    }

    /// Note: Zero can be positive or negative.
    fn is_positive(&self) -> bool {
        self.get_sign_field() == 0
    }

    /// Note: Zero can be positive or negative.
    fn is_negative(&self) -> bool {
        self.get_sign_field() != 0
    }
}
    <|endoftext|>