<commit_before>#![feature(in_band_lifetimes)]
//! This crate implements the [CloudEvents](https://cloudevents.io/) Spec for Rust.
//!
//! ```
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use cloudevents::{EventBuilder, AttributesReader, EventBuilderV10};
//! use chrono::{Utc, DateTime};
//! use url::Url;
//!
//! let event = EventBuilderV10::new()
//!     .id("my_event.my_application")
//!     .source("http://localhost:8080")
//!     .ty("example.demo")
//!     .time(Utc::now())
//!     .build()?;
//!
//! println!("CloudEvent Id: {}", event.id());
//! match event.time() {
//!     Some(t) => println!("CloudEvent Time: {}", t),
//!     None => println!("CloudEvent Time: None")
//! }
//! # Ok(())
//! # }
//! ```
//!
//! This crate includes:
//!
//! * The [`Event`] data structure, to represent CloudEvent (version 1.0 and 0.3)
//! * The [`EventBuilder`] trait and implementations, to create [`Event`] instances
//! * The implementation of [`serde::Serialize`] and [`serde::Deserialize`] for [`Event`] to serialize/deserialize CloudEvents to/from JSON
//! * Traits and utilities in [`message`] to implement Protocol Bindings
//! * Feature-guarded modules for various Protocol Binding implementations, e.g. actix, axum, reqwest, warp, rdkafka
//!
//! ## Feature flags
//!
//! Cloudevents uses a set of [feature flags] to conditionally compile
//! only the module associated with the Protocol Binding you need:
//!
//! - `actix`: Enables the [`binding::actix`] protocol binding module. This
//! extends the [`actix_web::HttpRequest`] with a
//! [`to_event`](binding::actix::HttpRequestExt::to_event) function, the
//! [`actix_web::dev::HttpResponseBuilder`] with an
//! [`event`](binding::actix::HttpResponseBuilderExt::event) function,
//! and implementations for [`actix_web::FromRequest`] and
//! [`actix_web::Responder`] in order to take advantage of actix-web's
//! [Extractors] and [Responders]
//! - `reqwest`: Enables the [`binding::reqwest`] protocol binding module.
//! - `warp`: Enables the [`binding::warp`] protocol binding module.
//! - `axum`: Enables the [`binding::axum`] protocol binding module.
//! - `rdkafka`: Enables the [`binding::rdkafka`] protocol binding module to
//! seamlessly consume/produce cloudevents within Kafka messages.
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//! [Extractors]: https://actix.rs/docs/extractors/
//! [Responders]: https://actix.rs/docs/handlers/

#![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.4.0")]
#![deny(rustdoc::broken_intra_doc_links)]

pub mod binding;
pub mod event;
pub mod message;

#[cfg(test)]
pub mod test;

pub use event::Data;
pub use event::Event;
pub use event::{AttributesReader, AttributesWriter};
pub use event::{EventBuilder, EventBuilderV03, EventBuilderV10};
<commit_msg>Remove useless `in_band_lifetimes` feature<commit_after>//! This crate implements the [CloudEvents](https://cloudevents.io/) Spec for Rust.
//!
//! ```
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use cloudevents::{EventBuilder, AttributesReader, EventBuilderV10};
//! use chrono::{Utc, DateTime};
//! use url::Url;
//!
//! let event = EventBuilderV10::new()
//!     .id("my_event.my_application")
//!     .source("http://localhost:8080")
//!     .ty("example.demo")
//!     .time(Utc::now())
//!     .build()?;
//!
//! println!("CloudEvent Id: {}", event.id());
//! match event.time() {
//!     Some(t) => println!("CloudEvent Time: {}", t),
//!     None => println!("CloudEvent Time: None")
//! }
//! # Ok(())
//! # }
//! ```
//!
//! This crate includes:
//!
//! * The [`Event`] data structure, to represent CloudEvent (version 1.0 and 0.3)
//! * The [`EventBuilder`] trait and implementations, to create [`Event`] instances
//! * The implementation of [`serde::Serialize`] and [`serde::Deserialize`] for [`Event`] to serialize/deserialize CloudEvents to/from JSON
//! * Traits and utilities in [`message`] to implement Protocol Bindings
//! * Feature-guarded modules for various Protocol Binding implementations, e.g. actix, axum, reqwest, warp, rdkafka
//!
//! ## Feature flags
//!
//! Cloudevents uses a set of [feature flags] to conditionally compile
//! only the module associated with the Protocol Binding you need:
//!
//! - `actix`: Enables the [`binding::actix`] protocol binding module. This
//! extends the [`actix_web::HttpRequest`] with a
//! [`to_event`](binding::actix::HttpRequestExt::to_event) function, the
//! [`actix_web::dev::HttpResponseBuilder`] with an
//! [`event`](binding::actix::HttpResponseBuilderExt::event) function,
//! and implementations for [`actix_web::FromRequest`] and
//! [`actix_web::Responder`] in order to take advantage of actix-web's
//! [Extractors] and [Responders]
//! - `reqwest`: Enables the [`binding::reqwest`] protocol binding module.
//! - `warp`: Enables the [`binding::warp`] protocol binding module.
//! - `axum`: Enables the [`binding::axum`] protocol binding module.
//! - `rdkafka`: Enables the [`binding::rdkafka`] protocol binding module to
//! seamlessly consume/produce cloudevents within Kafka messages.
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//! [Extractors]: https://actix.rs/docs/extractors/
//! [Responders]: https://actix.rs/docs/handlers/

#![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.4.0")]
#![deny(rustdoc::broken_intra_doc_links)]

pub mod binding;
pub mod event;
pub mod message;

#[cfg(test)]
pub mod test;

pub use event::Data;
pub use event::Event;
pub use event::{AttributesReader, AttributesWriter};
pub use event::{EventBuilder, EventBuilderV03, EventBuilderV10};
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};
use std::any::Any;
use std::rc::Rc;
use std::cmp::Ordering;

// TODO check whether hashes in rust vary by CPU endianness?
// Answer: they do, so maybe stop using Hash for this sometime
// ( https://doc.rust-lang.org/std/hash/trait.Hasher.html
// "represents the ability to hash an arbitrary stream of bytes").
#[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SiphashId {
  data: [u64; 2],
}
pub struct SiphashId_Generator {
  data: [SipHasher; 2],
}
impl Hasher for SiphashId_Generator {
  fn finish(&self) -> u64 {
    panic!()
  }//Hack: this is actually for generating SiphashId, not 64-bit
  fn write(&mut self, bytes: &[u8]) {
    self.data[0].write(bytes);
    self.data[1].write(bytes);
  }
  // TODO: should we implement the others for efficiency?
}
impl SiphashId_Generator {
  fn generate(&self) -> SiphashId {
    SiphashId { data: [self.data[0].finish(), self.data[1].finish()] }
  }
  fn new() -> SiphashId_Generator {
    SiphashId_Generator { data: [
      SipHasher::new_with_keys(0xb82a9426fd1a574f, 0x9d9d5b703dcb1bcc),
      SipHasher::new_with_keys(0x03e0d6037ff980a4, 0x65b790a0825b83bd),
      ] }
  }
}
// other possible names: hash_up_a_siphash_id?
fn collision_resistant_hash<T: Hash>(data: &T) -> SiphashId {
  let mut s = SiphashId_Generator::new();
  data.hash(&mut s);
  s.generate()
}

// TODO: Shouldn't "ordered type with minimum and maximum values" be a trait common to other situations as well? Find out if there's a standard name for that.
pub trait BaseTime: Clone + Ord {
  fn min_time() -> Self;
  fn max_time() -> Self;
}
impl BaseTime for i64 {
  fn min_time() -> i64 {
    i64::min_value()
  }
  fn max_time() -> i64 {
    i64::max_value()
  }
}

pub trait Field {
  type Data: Any;// = Self;

  /**
  Returns a constant identifier for the type, which must be 64 bits of random data.

  Thanks to the [birthday problem](https://en.wikipedia.org/wiki/Birthday_problem), this would have a >1% chance of a collision with a mere 700 million Field implementors. I don't think we need to worry about this. 128 bit IDs are necessary for entities, because computers can generate billions of them easily, but this isn't the same situation.

  It might seem desirable to default to a hash of the TypeId of Self, for the convenience of some implementations. However, Rust does not guarantee that the TypeId remains the same across different compilations or different compiler versions. And it certainly doesn't remain the same when you add or remove types from your code, which would be desirable for compatibility between different versions of your program. Also, the Rust interface for getting the TypeId is currently unstable. Using an explicit constant is simply better.

  TODO: change this into an associated constant once associated constants become stable.
  */
  fn unique_identifier() -> u64;

  /**
  Implementors MAY return true if first and second are indistinguishable.

  This is labeled "unsafe" because imperfect implementations can easily cause nondeterminism in the TimeSteward. Using the default is fine, and implementing it is only an optimization. Don't implement this unless you know what you're doing.

  This is similar to requiring Data to be PartialEq, but with an important difference. PartialEq only requires the comparison to be an equivalence relation, but does NOT require that (first == second) guarantee that there is no observable difference between the values. Therefore, trusting arbitrary implementations of PartialEq would be unsafe (in the sense that it would allow the TimeSteward to behave non-deterministically).

  TODO: perhaps we can create default implementations of this for POD types.
  TODO: can we create automated tests for implementations of this function?
  */
  fn guaranteed_equal__unsafe(first: &Self::Data, second: &Self::Data) -> bool {
    false
  }
}

#[derive (Clone, PartialEq, Eq, Hash)]
struct FieldId {
  entity: SiphashId,
  field: u64,
}

#[derive (Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct GenericExtendedTime<Base: BaseTime> {
  base: Base,
  iteration: u64,
  id: SiphashId,
}

fn beginning_of_moment<Base: BaseTime>(base_time: Base) -> GenericExtendedTime<Base> {
  GenericExtendedTime {
    base: base_time,
    iteration: 0,
    id: SiphashId { data: [0, 0] },
  }
}

fn extended_time_of_predicted_event<Base: BaseTime>(
                                       predictor_id: u64,
                                       entity_id: SiphashId,
                                       event_base_time: Base,
                                       when_event_was_predicted: &GenericExtendedTime<Base>)
                                       -> Option<GenericExtendedTime<Base>> {
  let id = collision_resistant_hash(&(predictor_id, entity_id));
  let iteration = match event_base_time.cmp(&when_event_was_predicted.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => 0,
    Ordering::Equal => {
      if id > when_event_was_predicted.id {
        when_event_was_predicted.iteration
      } else {
        when_event_was_predicted.iteration + 1
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    id: id,
    iteration: iteration,
  })
}

/**
This is intended to be implemented on an empty struct. Requiring Clone is a hack to work around [a compiler weakness](https://github.com/rust-lang/rust/issues/26925).
*/
pub trait Basics: Clone {
  type Time: BaseTime;
  type Constants;
}
type ExtendedTime<B: Basics> = GenericExtendedTime<B::Time>;

// Note: in the future, we expect we might use a custom hash table type that knows it can rely on SiphashId to already be random, so we don't need to hash it again. This also applies to FieldId, although there may be some complications in that case.
// (for now, we need to be able to hash full siphash ids to create other siphash ids.)
// ( Also -- do we ever try to hash GenericExtendedTime with id of 0 from beginning_of_moment.... )
// impl Hash for SiphashId {
//  fn hash<H: Hasher>(&self, state: &mut H) {
//    self.data[0].hash(state);
//  }
// }
// impl<Base: BaseTime> Hash for GenericExtendedTime<Base> {
//  fn hash<H: Hasher>(&self, state: &mut H) {
//    self.id.hash(state);
//  }
// }

pub trait Accessor<B: Basics> {
  fn get<F: Field>(&mut self, id: SiphashId) -> Option<&F::Data>;
  fn constants(&self) -> &B::Constants;
}

pub trait MomentaryAccessor<B: Basics>: Accessor<B> {
  fn now(&self) -> &B::Time;
}

pub trait Mutator<B: Basics>: MomentaryAccessor<B> {
  fn get_mut<F: Field>(&mut self, id: SiphashId) -> Option<&mut F::Data> where F::Data: Clone;
  fn set<F: Field>(&mut self, id: SiphashId, data: Option<F::Data>);
  fn random_bits(&mut self, num_bits: u32) -> u64;
  fn random_id(&mut self) -> SiphashId;
}
pub trait PredictorAccessor<B: Basics>: Accessor<B> {}
pub trait Snapshot<B: Basics>: MomentaryAccessor<B> {}

pub enum FiatEventOperationResult {
  Success,
  InvalidInput,
  InvalidTime,
}

pub trait TimeSteward<'a, B: Basics> {
  type S: Snapshot<B>;
  type Event;

  /**
  TimeSteward implementors are permitted, but not required, to discard old data in order to save memory. This may make the TimeSteward unusable at some points in its history.

  Newly created stewards should generally have valid_from() == B::Time::min_time().

  All implementors must obey certain restrictions on how other TimeSteward methods may change the result of valid_from(). Implementors may have their own methods that can alter this in customized ways, which should be documented with those individual methods.
  */
  fn valid_from(&self) -> B::Time;

  /**
  Inserts a fiat event at some point in the history.

  If time < valid_from(), this does nothing and returns InvalidTime. If there is already a fiat event with the same time and distinguisher, this does nothing and returns InvalidInput. Otherwise, it inserts the event and returns Success.

  steward.insert_fiat_event(time, _) must not return InvalidTime if time >= steward.valid_from().
  steward.insert_fiat_event() may not change steward.valid_from().
  */
  fn insert_fiat_event(&mut self,
                       time: B::Time,
                       distinguisher: u64,
                       event: Self::Event)
                       -> FiatEventOperationResult;

  /**
  Erases a fiat event that has been inserted previously.

  If time < valid_from(), this does nothing and returns InvalidTime. If there is no fiat event with the specified time and distinguisher, this does nothing and returns InvalidInput. Otherwise, it erases the event and returns Success.

  steward.erase_fiat_event(time, _) must not return InvalidTime if time >= steward.valid_from().
  steward.erase_fiat_event() may not change steward.valid_from().
  */
  fn erase_fiat_event(&mut self, time: B::Time, distinguisher: u64) -> FiatEventOperationResult;

  /**
  Returns a "snapshot" into the TimeSteward.

  The snapshot is guaranteed to be valid and unchanging for the full lifetime of the TimeSteward. It is specific to both the time argument, and the current collection of fiat events. Callers may freely call mutable methods of the same TimeSteward after taking a snapshot, without changing the contents of the snapshot.

  Each TimeSteward implementor determines exactly how to provide these guarantees. Implementors should provide individual guarantees about the processor-time bounds of snapshot operations.

  steward.snapshot_before(time) must return Some if time >= steward.valid_from().
  steward.snapshot_before(time) may not increase steward.valid_from() beyond time.
  */
  // note: we implement "before" and not "after" because we might be banning events that happen during max_time
  fn snapshot_before(&mut self, time: B::Time) -> Option<Self::S>;
}

pub trait FlatTimeSteward<'a, B: Basics>: TimeSteward<'a, B> {
  fn valid_strictly_between(&self) -> (B::Time, B::Time);
}

#[derive (Clone)]
enum Prediction<B: Basics, E> {
  Nothing,
  Immediately(E),
  At(B::Time, E),
}
struct Predictor<PredictorFn> {
  predictor_id: u64,
  field_id: u64,
  function: PredictorFn,
}

//type Event<M> = Rc<for<'d> Fn(&'d mut M)>;
//type PredictorFn<B: Basics, M: Mutator<B>, PA: PredictorAccessor<B>> =
//  Rc<for<'b, 'c> Fn(&'b mut PA, SiphashId) -> Prediction<B, Event<M>>>;

mod inefficient_flat_time_steward;
// mod simple_flat_time_steward;

#[test]
fn it_works() {}
<commit_msg>make things public that should be<commit_after>use std::hash::{Hash, Hasher, SipHasher};
use std::any::Any;
use std::rc::Rc;
use std::cmp::Ordering;

// TODO check whether hashes in rust vary by CPU endianness?
// Answer: they do, so maybe stop using Hash for this sometime
// ( https://doc.rust-lang.org/std/hash/trait.Hasher.html
// "represents the ability to hash an arbitrary stream of bytes").
#[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SiphashId {
  data: [u64; 2],
}
pub struct SiphashId_Generator {
  data: [SipHasher; 2],
}
impl Hasher for SiphashId_Generator {
  fn finish(&self) -> u64 {
    panic!()
  }//Hack: this is actually for generating SiphashId, not 64-bit
  fn write(&mut self, bytes: &[u8]) {
    self.data[0].write(bytes);
    self.data[1].write(bytes);
  }
  // TODO: should we implement the others for efficiency?
}
impl SiphashId_Generator {
  fn generate(&self) -> SiphashId {
    SiphashId { data: [self.data[0].finish(), self.data[1].finish()] }
  }
  fn new() -> SiphashId_Generator {
    SiphashId_Generator { data: [
      SipHasher::new_with_keys(0xb82a9426fd1a574f, 0x9d9d5b703dcb1bcc),
      SipHasher::new_with_keys(0x03e0d6037ff980a4, 0x65b790a0825b83bd),
      ] }
  }
}
// other possible names: hash_up_a_siphash_id?
pub fn collision_resistant_hash<T: Hash>(data: &T) -> SiphashId {
  let mut s = SiphashId_Generator::new();
  data.hash(&mut s);
  s.generate()
}

// TODO: Shouldn't "ordered type with minimum and maximum values" be a trait common to other situations as well? Find out if there's a standard name for that.
pub trait BaseTime: Clone + Ord {
  fn min_time() -> Self;
  fn max_time() -> Self;
}
impl BaseTime for i64 {
  fn min_time() -> i64 {
    i64::min_value()
  }
  fn max_time() -> i64 {
    i64::max_value()
  }
}

pub trait Field {
  type Data: Any;// = Self;

  /**
  Returns a constant identifier for the type, which must be 64 bits of random data.

  Thanks to the [birthday problem](https://en.wikipedia.org/wiki/Birthday_problem), this would have a >1% chance of a collision with a mere 700 million Field implementors. I don't think we need to worry about this. 128 bit IDs are necessary for entities, because computers can generate billions of them easily, but this isn't the same situation.

  It might seem desirable to default to a hash of the TypeId of Self, for the convenience of some implementations. However, Rust does not guarantee that the TypeId remains the same across different compilations or different compiler versions. And it certainly doesn't remain the same when you add or remove types from your code, which would be desirable for compatibility between different versions of your program. Also, the Rust interface for getting the TypeId is currently unstable. Using an explicit constant is simply better.

  TODO: change this into an associated constant once associated constants become stable.
  */
  fn unique_identifier() -> u64;

  /**
  Implementors MAY return true if first and second are indistinguishable.

  This is labeled "unsafe" because imperfect implementations can easily cause nondeterminism in the TimeSteward. Using the default is fine, and implementing it is only an optimization. Don't implement this unless you know what you're doing.

  This is similar to requiring Data to be PartialEq, but with an important difference. PartialEq only requires the comparison to be an equivalence relation, but does NOT require that (first == second) guarantee that there is no observable difference between the values. Therefore, trusting arbitrary implementations of PartialEq would be unsafe (in the sense that it would allow the TimeSteward to behave non-deterministically).

  TODO: perhaps we can create default implementations of this for POD types.
  TODO: can we create automated tests for implementations of this function?
  */
  fn guaranteed_equal__unsafe(first: &Self::Data, second: &Self::Data) -> bool {
    false
  }
}

#[derive (Clone, PartialEq, Eq, Hash)]
struct FieldId {
  entity: SiphashId,
  field: u64,
}

#[derive (Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct GenericExtendedTime<Base: BaseTime> {
  base: Base,
  iteration: u64,
  id: SiphashId,
}

fn beginning_of_moment<Base: BaseTime>(base_time: Base) -> GenericExtendedTime<Base> {
  GenericExtendedTime {
    base: base_time,
    iteration: 0,
    id: SiphashId { data: [0, 0] },
  }
}

fn extended_time_of_predicted_event<Base: BaseTime>(
                                       predictor_id: u64,
                                       entity_id: SiphashId,
                                       event_base_time: Base,
                                       when_event_was_predicted: &GenericExtendedTime<Base>)
                                       -> Option<GenericExtendedTime<Base>> {
  let id = collision_resistant_hash(&(predictor_id, entity_id));
  let iteration = match event_base_time.cmp(&when_event_was_predicted.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => 0,
    Ordering::Equal => {
      if id > when_event_was_predicted.id {
        when_event_was_predicted.iteration
      } else {
        when_event_was_predicted.iteration + 1
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    id: id,
    iteration: iteration,
  })
}

/**
This is intended to be implemented on an empty struct. Requiring Clone is a hack to work around [a compiler weakness](https://github.com/rust-lang/rust/issues/26925).
*/
pub trait Basics: Clone {
  type Time: BaseTime;
  type Constants;
}
type ExtendedTime<B: Basics> = GenericExtendedTime<B::Time>;

// Note: in the future, we expect we might use a custom hash table type that knows it can rely on SiphashId to already be random, so we don't need to hash it again. This also applies to FieldId, although there may be some complications in that case.
// (for now, we need to be able to hash full siphash ids to create other siphash ids.)
// ( Also -- do we ever try to hash GenericExtendedTime with id of 0 from beginning_of_moment.... )
// impl Hash for SiphashId {
//  fn hash<H: Hasher>(&self, state: &mut H) {
//    self.data[0].hash(state);
//  }
// }
// impl<Base: BaseTime> Hash for GenericExtendedTime<Base> {
//  fn hash<H: Hasher>(&self, state: &mut H) {
//    self.id.hash(state);
//  }
// }

pub trait Accessor<B: Basics> {
  fn get<F: Field>(&mut self, id: SiphashId) -> Option<&F::Data>;
  fn constants(&self) -> &B::Constants;
}

pub trait MomentaryAccessor<B: Basics>: Accessor<B> {
  fn now(&self) -> &B::Time;
}

pub trait Mutator<B: Basics>: MomentaryAccessor<B> {
  fn get_mut<F: Field>(&mut self, id: SiphashId) -> Option<&mut F::Data> where F::Data: Clone;
  fn set<F: Field>(&mut self, id: SiphashId, data: Option<F::Data>);
  fn random_bits(&mut self, num_bits: u32) -> u64;
  fn random_id(&mut self) -> SiphashId;
}
pub trait PredictorAccessor<B: Basics>: Accessor<B> {}
pub trait Snapshot<B: Basics>: MomentaryAccessor<B> {}

pub enum FiatEventOperationResult {
  Success,
  InvalidInput,
  InvalidTime,
}

pub trait TimeSteward<'a, B: Basics> {
  type S: Snapshot<B>;
  type Event;

  /**
  TimeSteward implementors are permitted, but not required, to discard old data in order to save memory. This may make the TimeSteward unusable at some points in its history.

  Newly created stewards should generally have valid_from() == B::Time::min_time().

  All implementors must obey certain restrictions on how other TimeSteward methods may change the result of valid_from(). Implementors may have their own methods that can alter this in customized ways, which should be documented with those individual methods.
  */
  fn valid_from(&self) -> B::Time;

  /**
  Inserts a fiat event at some point in the history.

  If time < valid_from(), this does nothing and returns InvalidTime. If there is already a fiat event with the same time and distinguisher, this does nothing and returns InvalidInput. Otherwise, it inserts the event and returns Success.

  steward.insert_fiat_event(time, _) must not return InvalidTime if time >= steward.valid_from().
  steward.insert_fiat_event() may not change steward.valid_from().
  */
  fn insert_fiat_event(&mut self,
                       time: B::Time,
                       distinguisher: u64,
                       event: Self::Event)
                       -> FiatEventOperationResult;

  /**
  Erases a fiat event that has been inserted previously.

  If time < valid_from(), this does nothing and returns InvalidTime. If there is no fiat event with the specified time and distinguisher, this does nothing and returns InvalidInput. Otherwise, it erases the event and returns Success.

  steward.erase_fiat_event(time, _) must not return InvalidTime if time >= steward.valid_from().
  steward.erase_fiat_event() may not change steward.valid_from().
  */
  fn erase_fiat_event(&mut self, time: B::Time, distinguisher: u64) -> FiatEventOperationResult;

  /**
  Returns a "snapshot" into the TimeSteward.

  The snapshot is guaranteed to be valid and unchanging for the full lifetime of the TimeSteward. It is specific to both the time argument, and the current collection of fiat events. Callers may freely call mutable methods of the same TimeSteward after taking a snapshot, without changing the contents of the snapshot.

  Each TimeSteward implementor determines exactly how to provide these guarantees. Implementors should provide individual guarantees about the processor-time bounds of snapshot operations.

  steward.snapshot_before(time) must return Some if time >= steward.valid_from().
  steward.snapshot_before(time) may not increase steward.valid_from() beyond time.
  */
  // note: we implement "before" and not "after" because we might be banning events that happen during max_time
  fn snapshot_before(&mut self, time: B::Time) -> Option<Self::S>;
}

pub trait FlatTimeSteward<'a, B: Basics>: TimeSteward<'a, B> {
  fn valid_strictly_between(&self) -> (B::Time, B::Time);
}

#[derive (Clone)]
enum Prediction<B: Basics, E> {
  Nothing,
  Immediately(E),
  At(B::Time, E),
}
struct Predictor<PredictorFn> {
  predictor_id: u64,
  field_id: u64,
  function: PredictorFn,
}

//type Event<M> = Rc<for<'d> Fn(&'d mut M)>;
//type PredictorFn<B: Basics, M: Mutator<B>, PA: PredictorAccessor<B>> =
//  Rc<for<'b, 'c> Fn(&'b mut PA, SiphashId) -> Prediction<B, Event<M>>>;

pub mod inefficient_flat_time_steward;
// pub mod simple_flat_time_steward;

#[test]
fn it_works() {}
<|endoftext|>


<commit_before>use std::simd;

pub type usize = uint;

/// A SIMD vector, storing `count()` elements of type `Item`.
pub trait Vector {
    /// The type that this vector contains.
    type Item;

    /// Return the number of items in `self`.
    fn count(&self) -> usize;
}

macro_rules! vector_impl {
    ($( $main: ident, $item: ty, $count: expr; )* ) => {
        $(
            impl Vector for simd::$main {
                type Item = $item;
                fn count(&self) -> usize {
                    $count
                }
            }
            )*
    }
}

vector_impl! {
    i8x16, i8, 16;
    u8x16, u8, 16;

    i16x8, i16, 8;
    u16x8, u16, 8;

    i32x4, i32, 4;
    u32x4, u32, 4;

    i64x2, i64, 2;
    u64x2, u64, 2;

    f32x4, f32, 4;
    f64x2, f64, 2;
}
<commit_msg>Add some module docs.<commit_after>//! Functionality for working with SIMD registers and instructions.
//!
//! [Source](https://github.com/huonw/simd), [crates.io](https://crates.io/crates/simd)

use std::simd;

pub type usize = uint;

/// A SIMD vector, storing `count()` elements of type `Item`.
pub trait Vector {
    /// The type that this vector contains.
    type Item;

    /// Return the number of items in `self`.
    fn count(&self) -> usize;
}

macro_rules! vector_impl {
    ($( $main: ident, $item: ty, $count: expr; )* ) => {
        $(
            impl Vector for simd::$main {
                type Item = $item;
                fn count(&self) -> usize {
                    $count
                }
            }
            )*
    }
}

vector_impl! {
    i8x16, i8, 16;
    u8x16, u8, 16;

    i16x8, i16, 8;
    u16x8, u16, 8;

    i32x4, i32, 4;
    u32x4, u32, 4;

    i64x2, i64, 2;
    u64x2, u64, 2;

    f32x4, f32, 4;
    f64x2, f64, 2;
}
<|endoftext|>


<commit_before>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next(n_i: &[usize], n_j: &[usize], x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i[a], n_j[b]);

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

// Calculates x[k+1]
fn next_x(x: &DMat<f32>,
          new_x: &mut DMat<f32>,
          in_a: &[Vec<usize>],
          in_b: &[Vec<usize>],
          out_a: &[Vec<usize>],
          out_b: &[Vec<usize>]) {
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            new_x[(i, j)] = (s_next(&in_a[i], &in_b[j], x) + s_next(&out_a[i], &out_b[j], x)) / 2.0;
        }
    }
}

/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix(in_a: &[Vec<usize>],
                                in_b: &[Vec<usize>],
                                out_a: &[Vec<usize>],
                                out_b: &[Vec<usize>],
                                eps: f32,
                                stop_after_iter: usize)
                                -> (usize, DMat<f32>) {
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        // XXX: Is that correct?
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x, &mut new_x, &in_a, &in_b, &out_a, &out_b);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score(in_a: &[Vec<usize>],
                               in_b: &[Vec<usize>],
                               out_a: &[Vec<usize>],
                               out_b: &[Vec<usize>],
                               eps: f32,
                               stop_after_iter: usize,
                               score_method: ScoreMethod)
                               -> (usize, f32) {
    let (iter, x) = neighbor_matching_matrix(in_a, in_b, out_a, out_b, eps, stop_after_iter);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<commit_msg>Nodes can be of different color.<commit_after>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next(n_i: &[usize], n_j: &[usize], x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i[a], n_j[b]);

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<usize>],
             in_b: &[Vec<usize>],
             out_a: &[Vec<usize>],
             out_b: &[Vec<usize>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(&in_a[i], &in_b[j], x) + s_next(&out_a[i], &out_b[j], x)) /
                            2.0;
        }
    }
}

#[inline]
/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix<F>(in_a: &[Vec<usize>],
                                   in_b: &[Vec<usize>],
                                   out_a: &[Vec<usize>],
                                   out_b: &[Vec<usize>],
                                   eps: f32,
                                   stop_after_iter: usize,
                                   node_color_scale: &F)
                                   -> (usize, DMat<f32>)
    where F: Fn((usize, usize)) -> f32
{
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        node_color_scale((i, j)) *
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x,
               &mut new_x,
               &in_a,
               &in_b,
               &out_a,
               &out_b,
               node_color_scale);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

#[inline]
/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score<F>(in_a: &[Vec<usize>],
                                  in_b: &[Vec<usize>],
                                  out_a: &[Vec<usize>],
                                  out_b: &[Vec<usize>],
                                  eps: f32,
                                  stop_after_iter: usize,
                                  node_color_scale: &F,
                                  score_method: ScoreMethod)
                                  -> (usize, f32)
    where F: Fn((usize, usize)) -> f32
{
    let (iter, x) = neighbor_matching_matrix(in_a,
                                             in_b,
                                             out_a,
                                             out_b,
                                             eps,
                                             stop_after_iter,
                                             node_color_scale);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100, &|_| 1.0);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1, &|_| 1.0);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<|endoftext|>


<commit_before>extern crate nalgebra;
extern crate rand;

pub mod csv;
pub mod koe;
pub mod cb;
pub mod tick;

pub use cb::*;
pub use csv::*;
pub use koe::*;
pub use tick::*;

#[cfg(test)]
mod tests {
    use std::f64::consts::PI;
    use std::rc::*;
    use cb::*;
    use csv::*;
    use koe::*;
    use rand::*;
    use nalgebra::*;

    #[test]
    fn koe_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut a_ok = 0;
        let mut e_ok = 0;
        let mut inc_ok = 0;
        let mut lan_ok = 0;
        let mut ap_ok = 0;
        let mut m0_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CB>::new(cb));
            let csv0 = CSV::from_koe(koe0.clone());
            let koe1 = KOE::from_csv(csv0);
            if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
                a_ok += 1;
            }
            if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
                e_ok += 1;
            }
            if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
                inc_ok += 1;
            }
            if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
                lan_ok += 1;
            }
            if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
                ap_ok += 1;
            }
            if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
                m0_ok += 1;
            }
        }
        let a_ok_f = a_ok as f32 / iterations as f32;
        let e_ok_f = e_ok as f32 / iterations as f32;
        let inc_ok_f = inc_ok as f32 / iterations as f32;
        let lan_ok_f = lan_ok as f32 / iterations as f32;
        let ap_ok_f = ap_ok as f32 / iterations as f32;
        let m0_ok_f = m0_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if a_ok_f < threshold {
            println!("a_ok_f = {}", a_ok_f);
            if !failed {
                failed = true;
            }
        }
        if e_ok_f < threshold {
            println!("e_ok_f = {}", e_ok_f);
            if !failed {
                failed = true;
            }
        }
        if inc_ok_f < threshold {
            println!("inc_ok_f = {}", inc_ok_f);
            if !failed {
                failed = true;
            }
        }
        if lan_ok_f < threshold {
            println!("lan_ok_f = {}", lan_ok_f);
            if !failed {
                failed = true;
            }
        }
        if ap_ok_f < threshold {
            println!("ap_ok_f = {}", ap_ok_f);
            if !failed {
                failed = true;
            }
        }
        if m0_ok_f < threshold {
            println!("m0_ok_f = {}", m0_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for one of the parameters is below threshold");
        }
    }

    #[test]
    fn csv_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut r_ok = 0;
        let mut v_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CB>::new(cb));
            let csv0 = CSV::from_koe(koe0);
            let koe1 = KOE::from_csv(csv0.clone());
            let csv1 = CSV::from_koe(koe1);
            if csv0.r.approx_eq_eps(&csv1.r, &eps) {
                r_ok += 1;
            }
            if csv0.v.approx_eq_eps(&csv1.v, &eps) {
                v_ok += 1;
            }
        }
        let r_ok_f = r_ok as f32 / iterations as f32;
        let v_ok_f = v_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if r_ok_f < threshold {
            println!("r_ok_f = {}", r_ok_f);
            if !failed {
                failed = true;
            }
        }
        if v_ok_f < threshold {
            println!("v_ok_f = {}", v_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for some of the parameters is below the threshold");
        }
    }

    fn get_random_cb() -> CB {
        let mut rng = thread_rng();
        let k = normalize(
                &Vec3::new( // Up vector
                    rng.gen_range(0.1, 1.0),
                    rng.gen_range(0.1, 1.0),
                    rng.gen_range(0.1, 1.0)
                    )
            );
        let arbitrary_vec = Vec3::<f64>::new(1.0, 0.0, 0.0);
        let i = normalize(&cross(&arbitrary_vec, &k));
        let j = normalize(&cross(&k, &i));
        CB::new(
            rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
            i,
            j,
            k
        )
    }

    fn get_random_koe(cb: Rc<CB>) -> KOE {
        let mut rng = thread_rng();
        let ecc = rng.gen_range(0.0, 1.0);
        let inc = rng.gen_range(0.0, PI);
        let mut lan = rng.gen_range(0.0, 2.0*PI);
        let mut ap = rng.gen_range(0.0, 2.0*PI);
        if approx_eq(&ecc, &0.0) {
            ap = 0.0;
        }
        if approx_eq(&inc, &0.0) {
            lan = 0.0;
            ap = 0.0;
            if !approx_eq(&ecc, &0.0) {
                ap = rng.gen_range(0.0, 2.0*PI);
            }
        }
        KOE::new(
            rng.gen_range(1.0, 1.0e10), // Semi major axis
            ecc, // Eccentricity
            inc, // Inclination
            lan, // Longitude of Ascending Node
            ap,  // Argument of Periapsis
            rng.gen_range(-PI, PI), // Mean anomaly
            cb
        )
    }
}
<commit_msg>Refactor get_random_cb function<commit_after>extern crate nalgebra;
extern crate rand;

pub mod csv;
pub mod koe;
pub mod cb;
pub mod tick;

pub use cb::*;
pub use csv::*;
pub use koe::*;
pub use tick::*;

#[cfg(test)]
mod tests {
    use std::f64::consts::PI;
    use std::rc::*;
    use cb::*;
    use csv::*;
    use koe::*;
    use rand::*;
    use nalgebra::*;

    #[test]
    fn koe_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut a_ok = 0;
        let mut e_ok = 0;
        let mut inc_ok = 0;
        let mut lan_ok = 0;
        let mut ap_ok = 0;
        let mut m0_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CB>::new(cb));
            let csv0 = CSV::from_koe(koe0.clone());
            let koe1 = KOE::from_csv(csv0);
            if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
                a_ok += 1;
            }
            if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
                e_ok += 1;
            }
            if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
                inc_ok += 1;
            }
            if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
                lan_ok += 1;
            }
            if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
                ap_ok += 1;
            }
            if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
                m0_ok += 1;
            }
        }
        let a_ok_f = a_ok as f32 / iterations as f32;
        let e_ok_f = e_ok as f32 / iterations as f32;
        let inc_ok_f = inc_ok as f32 / iterations as f32;
        let lan_ok_f = lan_ok as f32 / iterations as f32;
        let ap_ok_f = ap_ok as f32 / iterations as f32;
        let m0_ok_f = m0_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if a_ok_f < threshold {
            println!("a_ok_f = {}", a_ok_f);
            if !failed {
                failed = true;
            }
        }
        if e_ok_f < threshold {
            println!("e_ok_f = {}", e_ok_f);
            if !failed {
                failed = true;
            }
        }
        if inc_ok_f < threshold {
            println!("inc_ok_f = {}", inc_ok_f);
            if !failed {
                failed = true;
            }
        }
        if lan_ok_f < threshold {
            println!("lan_ok_f = {}", lan_ok_f);
            if !failed {
                failed = true;
            }
        }
        if ap_ok_f < threshold {
            println!("ap_ok_f = {}", ap_ok_f);
            if !failed {
                failed = true;
            }
        }
        if m0_ok_f < threshold {
            println!("m0_ok_f = {}", m0_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for one of the parameters is below threshold");
        }
    }

    #[test]
    fn csv_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut r_ok = 0;
        let mut v_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CB>::new(cb));
            let csv0 = CSV::from_koe(koe0);
            let koe1 = KOE::from_csv(csv0.clone());
            let csv1 = CSV::from_koe(koe1);
            if csv0.r.approx_eq_eps(&csv1.r, &eps) {
                r_ok += 1;
            }
            if csv0.v.approx_eq_eps(&csv1.v, &eps) {
                v_ok += 1;
            }
        }
        let r_ok_f = r_ok as f32 / iterations as f32;
        let v_ok_f = v_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if r_ok_f < threshold {
            println!("r_ok_f = {}", r_ok_f);
            if !failed {
                failed = true;
            }
        }
        if v_ok_f < threshold {
            println!("v_ok_f = {}", v_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for some of the parameters is below the threshold");
        }
    }

    fn get_random_cb() -> CB {
        let mut rng = thread_rng();
        let rand_rot_vec =
            normalize(
                &Vec3::<f64>::new( // Up vector
                    rng.gen_range(-1.0, 1.0),
                    rng.gen_range(-1.0, 1.0),
                    rng.gen_range(-1.0, 1.0)
                    )
            )*rng.gen_range(0.0, 2.0*PI);

        let rand_rot = Rot3::<f64>::new(rand_rot_vec);

        let i = Vec3::<f64>::new(1.0, 0.0, 0.0);
        let j = Vec3::<f64>::new(0.0, 1.0, 0.0);
        let k = Vec3::<f64>::new(0.0, 0.0, 1.0);

        let i = rand_rot.transform(&i);
        let j = rand_rot.transform(&j);
        let k = rand_rot.transform(&k);

        CB::new(
            rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
            i,
            j,
            k
        )
    }

    fn get_random_koe(cb: Rc<CB>) -> KOE {
        let mut rng = thread_rng();
        let ecc = rng.gen_range(0.0, 1.0);
        let inc = rng.gen_range(0.0, PI);
        let mut lan = rng.gen_range(0.0, 2.0*PI);
        let mut ap = rng.gen_range(0.0, 2.0*PI);
        if approx_eq(&ecc, &0.0) {
            ap = 0.0;
        }
        if approx_eq(&inc, &0.0) {
            lan = 0.0;
            ap = 0.0;
            if !approx_eq(&ecc, &0.0) {
                ap = rng.gen_range(0.0, 2.0*PI);
            }
        }
        KOE::new(
            rng.gen_range(1.0, 1.0e10), // Semi major axis
            ecc, // Eccentricity
            inc, // Inclination
            lan, // Longitude of Ascending Node
            ap,  // Argument of Periapsis
            rng.gen_range(-PI, PI), // Mean anomaly
            cb
        )
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
extern crate conduit;
extern crate route_recognizer as router;

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use router::{Match, Router};

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub struct RouterError(String);

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    #[allow(clippy::borrowed_box)]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path),
            None => Err(format!("No router found for {:?}", method)),
        }
        .map_err(RouterError)
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e.0);
                    return Err(box_error(e));
                }
            }
        };

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(m.params().clone());
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params(req: &dyn RequestExt) -> &router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;
    extern crate lazy_static;
    extern crate tracing_subscriber;

    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder, RoutePattern};

    use self::conduit_test::ResponseExt;
    use conduit::{
        Body, Extensions, Handler, HeaderMap, Host, Method, Response, Scheme, StatusCode, Version,
    };

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: Extensions::new(),
                method,
            }
        }
    }

    impl conduit::RequestExt for RequestSentinel {
        fn http_version(&self) -> Version {
            unimplemented!()
        }
        fn method(&self) -> &Method {
            &self.method
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host(&self) -> Host<'_> {
            unimplemented!()
        }
        fn virtual_root(&self) -> Option<&str> {
            unimplemented!()
        }
        fn path(&self) -> &str {
            &self.path
        }
        fn path_mut(&mut self) -> &mut String {
            &mut self.path
        }
        fn query_string(&self) -> Option<&str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers(&self) -> &HeaderMap {
            unimplemented!()
        }
        fn body(&mut self) -> &mut dyn io::Read {
            unimplemented!()
        }
        fn extensions(&self) -> &Extensions {
            &self.extensions
        }
        fn mut_extensions(&mut self) -> &mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn nonexistent_route() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    #[test]
    fn catch_all() {
        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = RequestSentinel::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<commit_msg>Avoid a String allocation on the error path<commit_after>#![warn(rust_2018_idioms)]
extern crate conduit;
extern crate route_recognizer as router;

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use router::{Match, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(m.params().clone());
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params(req: &dyn RequestExt) -> &router::Params {
    req.extensions()
        .find::<router::Params>()
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;
    extern crate lazy_static;
    extern crate tracing_subscriber;

    use std::io;
    use std::net::SocketAddr;

    use {RequestParams, RouteBuilder, RoutePattern};

    use self::conduit_test::ResponseExt;
    use conduit::{
        Body, Extensions, Handler, HeaderMap, Host, Method, Response, Scheme, StatusCode, Version,
    };

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: Extensions::new(),
                method,
            }
        }
    }

    impl conduit::RequestExt for RequestSentinel {
        fn http_version(&self) -> Version {
            unimplemented!()
        }
        fn method(&self) -> &Method {
            &self.method
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host(&self) -> Host<'_> {
            unimplemented!()
        }
        fn virtual_root(&self) -> Option<&str> {
            unimplemented!()
        }
        fn path(&self) -> &str {
            &self.path
        }
        fn path_mut(&mut self) -> &mut String {
            &mut self.path
        }
        fn query_string(&self) -> Option<&str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers(&self) -> &HeaderMap {
            unimplemented!()
        }
        fn body(&mut self) -> &mut dyn io::Read {
            unimplemented!()
        }
        fn extensions(&self) -> &Extensions {
            &self.extensions
        }
        fn mut_extensions(&mut self) -> &mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn nonexistent_route() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    #[test]
    fn catch_all() {
        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = RequestSentinel::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<|endoftext|>


<commit_before>#![feature(ip_addr)]

use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

// A network
#[derive(Debug)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv4Network {
    fn new(addr: Ipv4Addr, prefix: u8) -> Ipv4Network {
        Ipv4Network { addr: addr, prefix: prefix }
    }

    fn ip(&self) -> &Ipv4Addr {
        &(self.addr)
    }

    fn prefix(&self) -> u8 {
        self.prefix
    }

    fn mask(&self) -> u32 {
        let prefix = self.prefix;
        !(0xffffffff >> prefix)
    }

    fn mask_to_string(&self) -> String {
        let mask = self.mask();
        Ipv4Network::int_to_ip(mask).to_string()
    }

    fn ip_to_int(&self, addr: Ipv4Addr) -> u32 {
        let ip = addr.octets();
        (ip[0] as u32) << 24 + (ip[1] as u32) << 16 + (ip[2] as u32) << 8 + (ip[3] as u32)
    }

    fn int_to_ip(ip: u32) -> Ipv4Addr {
        Ipv4Addr::new(((ip >> 24) & 0xff) as u8, ((ip >> 16) & 0xff) as u8,
                     ((ip >> 8) & 0xff) as u8, (ip & 0xff) as u8)
    }
}

impl Ipv6Network {
    fn new(addr: Ipv6Addr, prefix: u8) -> Ipv6Network {
        Ipv6Network { addr: addr, prefix: prefix }
    }

    fn ip(&self) -> &Ipv6Addr {
        &(self.addr)
    }

    fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> IpNetwork {
        match ip {
            IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::new(a, prefix)),
            IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::new(a, prefix)),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(*a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(*a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}

impl fmt::Debug for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

impl fmt::Debug for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::{Ipv4Addr, Ipv6Addr};
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        assert_eq!(cidr.mask(), 4294967288);
    }

    #[test]
    fn mask_string_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        assert_eq!(cidr.mask_to_string(), "255.255.255.248");
    }
}
<commit_msg>Make ip_to_int a static method<commit_after>#![feature(ip_addr)]

use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

// A network
#[derive(Debug)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv4Network {
    fn new(addr: Ipv4Addr, prefix: u8) -> Ipv4Network {
        Ipv4Network { addr: addr, prefix: prefix }
    }

    fn ip(&self) -> &Ipv4Addr {
        &(self.addr)
    }

    fn prefix(&self) -> u8 {
        self.prefix
    }

    fn mask(&self) -> u32 {
        let prefix = self.prefix;
        !(0xffffffff >> prefix)
    }

    fn mask_to_string(&self) -> String {
        let mask = self.mask();
        Ipv4Network::int_to_ip(mask).to_string()
    }

    fn ip_to_int(addr: Ipv4Addr) -> u32 {
        let ip = addr.octets();
        (ip[0] as u32) << 24 + (ip[1] as u32) << 16 + (ip[2] as u32) << 8 + (ip[3] as u32)
    }

    fn int_to_ip(ip: u32) -> Ipv4Addr {
        Ipv4Addr::new(((ip >> 24) & 0xff) as u8, ((ip >> 16) & 0xff) as u8,
                     ((ip >> 8) & 0xff) as u8, (ip & 0xff) as u8)
    }
}

impl Ipv6Network {
    fn new(addr: Ipv6Addr, prefix: u8) -> Ipv6Network {
        Ipv6Network { addr: addr, prefix: prefix }
    }

    fn ip(&self) -> &Ipv6Addr {
        &(self.addr)
    }

    fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> IpNetwork {
        match ip {
            IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::new(a, prefix)),
            IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::new(a, prefix)),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(*a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(*a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}

impl fmt::Debug for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

impl fmt::Debug for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::{Ipv4Addr, Ipv6Addr};
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24);
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        assert_eq!(cidr.mask(), 4294967288);
    }

    #[test]
    fn mask_string_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29);
        assert_eq!(cidr.mask_to_string(), "255.255.255.248");
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]

use std::default::Default;
use std::cmp::Ordering;
use std::cell::Cell;
use std::hash::{self, Hash};
use std::collections::hash_map::Hasher;
use std::collections::HashMap;
use std::collections::BinaryHeap;
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};
use std::fmt;
use std::ops::{Add, Deref};

pub use scored::MinScored;
pub use graphmap::GraphMap;
pub use ograph::OGraph;

pub use self::EdgeDirection::{Outgoing, Incoming};
pub use visit::{
    Bfs,
    BfsIter,
    Dfs,
    DfsIter,
};
use visit::VisitMap;

mod scored;
pub mod graphmap;
pub mod ograph;
pub mod visit;

pub mod unionfind;

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction
#[derive(Copy, Clone, Show, PartialEq)]
pub enum EdgeDirection {
    /// A **Outgoing** edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An **Incoming** edge is an inbound edge *to* the current node.
    Incoming = 1
}

/// A reference that is hashed and compared by its pointer value.
pub struct Ptr<'b, T: 'b>(pub &'b T);

impl<'b, T> Copy for Ptr<'b, T> {}
impl<'b, T> Clone for Ptr<'b, T>
{
    fn clone(&self) -> Self { *self }
}

fn ptreq<T>(a: &T, b: &T) -> bool {
    a as *const _ == b as *const _
}

impl<'b, T> PartialEq for Ptr<'b, T>
{
    /// Ptr compares by pointer equality, i.e if they point to the same value
    fn eq(&self, other: &Ptr<'b, T>) -> bool {
        ptreq(self.0, other.0)
    }
}

impl<'b, T> PartialOrd for Ptr<'b, T>
{
    fn partial_cmp(&self, other: &Ptr<'b, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'b, T> Ord for Ptr<'b, T>
{
    /// Ptr is ordered by pointer value, i.e. an arbitrary but stable and total order.
    fn cmp(&self, other: &Ptr<'b, T>) -> Ordering {
        let a = self.0 as *const _;
        let b = other.0 as *const _;
        a.cmp(&b)
    }
}

impl<'b, T> Deref for Ptr<'b, T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        self.0
    }
}

impl<'b, T> Eq for Ptr<'b, T> {}

impl<'b, T, H: hash::Writer + hash::Hasher> Hash<H> for Ptr<'b, T>
{
    fn hash(&self, st: &mut H)
    {
        let ptr = (self.0) as *const _;
        ptr.hash(st)
    }
}

impl<'b, T: fmt::Show> fmt::Show for Ptr<'b, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Dijkstra's shortest path algorithm.
pub fn dijkstra<'a, G, N, K, F, Edges>(graph: &'a G,
                                       start: N,
                                       goal: Option<N>,
                                       mut edges: F) -> HashMap<N, K> where
    G: visit::Visitable<NodeId=N>,
    N: Clone + Eq + Hash<Hasher>,
    K: Default + Add<Output=K> + Copy + PartialOrd,
    F: FnMut(&'a G, N) -> Edges,
    Edges: Iterator<Item=(N, K)>,
    <G as visit::Visitable>::Map: VisitMap<N>,
{
    let mut visited = graph.visit_map();
    let mut scores = HashMap::new();
    let mut predecessor = HashMap::new();
    let mut visit_next = BinaryHeap::new();
    let zero_score: K = Default::default();
    scores.insert(start.clone(), zero_score);
    visit_next.push(MinScored(zero_score, start));
    while let Some(MinScored(node_score, node)) = visit_next.pop() {
        if visited.contains(&node) {
            continue
        }
        for (next, edge) in edges(graph, node.clone()) {
            if visited.contains(&next) {
                continue
            }
            let mut next_score = node_score + edge;
            match scores.entry(next.clone()) {
                Occupied(ent) => if next_score < *ent.get() {
                    *ent.into_mut() = next_score;
                    predecessor.insert(next.clone(), node.clone());
                } else {
                    next_score = *ent.get();
                },
                Vacant(ent) => {
                    ent.insert(next_score);
                    predecessor.insert(next.clone(), node.clone());
                }
            }
            visit_next.push(MinScored(next_score, next));
        }
        if goal.as_ref() == Some(&node) {
            break
        }
        visited.visit(node);
    }
    scores
}

#[derive(Show)]
pub struct Node<T>(pub T);

pub struct NodeCell<T: Copy>(pub Cell<T>);

impl<T: Copy> Deref for NodeCell<T> {
    type Target = Cell<T>;
    #[inline]
    fn deref(&self) -> &Cell<T> {
        &self.0
    }
}

impl<T: Copy + fmt::Show> fmt::Show for NodeCell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Node({:?})", self.0.get())
    }
}
<commit_msg>Remove cruft but keep Ptr around<commit_after>#![allow(unstable)]

use std::default::Default;
use std::cmp::Ordering;
use std::cell::Cell;
use std::hash::{self, Hash};
use std::collections::hash_map::Hasher;
use std::collections::HashMap;
use std::collections::BinaryHeap;
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};
use std::fmt;
use std::ops::{Add, Deref};

pub use scored::MinScored;
pub use graphmap::GraphMap;
pub use ograph::OGraph;

pub use self::EdgeDirection::{Outgoing, Incoming};
pub use visit::{
    Bfs,
    BfsIter,
    Dfs,
    DfsIter,
};
use visit::VisitMap;

mod scored;
pub mod graphmap;
pub mod ograph;
pub mod visit;

pub mod unionfind;

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction
#[derive(Copy, Clone, Show, PartialEq)]
pub enum EdgeDirection {
    /// A **Outgoing** edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An **Incoming** edge is an inbound edge *to* the current node.
    Incoming = 1
}

/// A reference that is hashed and compared by its pointer value.
pub struct Ptr<'b, T: 'b>(pub &'b T);

impl<'b, T> Copy for Ptr<'b, T> {}
impl<'b, T> Clone for Ptr<'b, T>
{
    fn clone(&self) -> Self { *self }
}

fn ptreq<T>(a: &T, b: &T) -> bool {
    a as *const _ == b as *const _
}

impl<'b, T> PartialEq for Ptr<'b, T>
{
    /// Ptr compares by pointer equality, i.e if they point to the same value
    fn eq(&self, other: &Ptr<'b, T>) -> bool {
        ptreq(self.0, other.0)
    }
}

impl<'b, T> PartialOrd for Ptr<'b, T>
{
    fn partial_cmp(&self, other: &Ptr<'b, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'b, T> Ord for Ptr<'b, T>
{
    /// Ptr is ordered by pointer value, i.e. an arbitrary but stable and total order.
    fn cmp(&self, other: &Ptr<'b, T>) -> Ordering {
        let a = self.0 as *const _;
        let b = other.0 as *const _;
        a.cmp(&b)
    }
}

impl<'b, T> Deref for Ptr<'b, T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        self.0
    }
}

impl<'b, T> Eq for Ptr<'b, T> {}

impl<'b, T, H: hash::Writer + hash::Hasher> Hash<H> for Ptr<'b, T>
{
    fn hash(&self, st: &mut H)
    {
        let ptr = (self.0) as *const _;
        ptr.hash(st)
    }
}

impl<'b, T: fmt::Show> fmt::Show for Ptr<'b, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Dijkstra's shortest path algorithm.
pub fn dijkstra<'a, G, N, K, F, Edges>(graph: &'a G,
                                       start: N,
                                       goal: Option<N>,
                                       mut edges: F) -> HashMap<N, K> where
    G: visit::Visitable<NodeId=N>,
    N: Clone + Eq + Hash<Hasher>,
    K: Default + Add<Output=K> + Copy + PartialOrd,
    F: FnMut(&'a G, N) -> Edges,
    Edges: Iterator<Item=(N, K)>,
    <G as visit::Visitable>::Map: VisitMap<N>,
{
    let mut visited = graph.visit_map();
    let mut scores = HashMap::new();
    let mut predecessor = HashMap::new();
    let mut visit_next = BinaryHeap::new();
    let zero_score: K = Default::default();
    scores.insert(start.clone(), zero_score);
    visit_next.push(MinScored(zero_score, start));
    while let Some(MinScored(node_score, node)) = visit_next.pop() {
        if visited.contains(&node) {
            continue
        }
        for (next, edge) in edges(graph, node.clone()) {
            if visited.contains(&next) {
                continue
            }
            let mut next_score = node_score + edge;
            match scores.entry(next.clone()) {
                Occupied(ent) => if next_score < *ent.get() {
                    *ent.into_mut() = next_score;
                    predecessor.insert(next.clone(), node.clone());
                } else {
                    next_score = *ent.get();
                },
                Vacant(ent) => {
                    ent.insert(next_score);
                    predecessor.insert(next.clone(), node.clone());
                }
            }
            visit_next.push(MinScored(next_score, next));
        }
        if goal.as_ref() == Some(&node) {
            break
        }
        visited.visit(node);
    }
    scores
}
<|endoftext|>