<commit_before>//! Freshening is the process of replacing unknown variables with fresh types. The idea is that
//! the type, after freshening, contains no inference variables but instead contains either a
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
//!
//! Freshening is used primarily to get a good type for inserting into a cache. The result
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
//!
//! To handle closures, freshened types also have to contain the signature and kind of any
//! closure in the local inference context, as otherwise the cache key might be invalidated.
//! The way this is done is somewhat hacky - the closure signature is appended to the substs,
//! as well as the closure kind "encoded" as a type. Also, special handling is needed when
//! the closure signature contains a reference to the original closure.
//!
//! Note that you should be careful not to allow the output of freshening to leak to the user in
//! error messages or in any other form. Freshening is only really useful as an internal detail.
//!
//! Because of the manipulation required to handle closures, doing arbitrary operations on
//! freshened types is not recommended. However, in addition to doing equality/hash
//! comparisons (for caching), it is possible to do a `ty::_match` operation between
//! 2 freshened types - this works even with the closure encoding.
//!
//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
//! account when making type-overloaded decisions. This is important because of the design of the
//! region inferencer, which is not based on unification but rather on accumulating and then
//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
//! inferencer knows "so far".

use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::fold::TypeFolder;
use crate::util::nodemap::FxHashMap;

use std::collections::hash_map::Entry;

use super::InferCtxt;
use super::unify_key::ToType;

pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
    freshen_count: u32,
    freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
}

impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
               -> TypeFreshener<'a, 'gcx, 'tcx> {
        TypeFreshener {
            infcx,
            freshen_count: 0,
            freshen_map: Default::default(),
        }
    }

    fn freshen<F>(&mut self,
                  opt_ty: Option<Ty<'tcx>>,
                  key: ty::InferTy,
                  freshener: F)
                  -> Ty<'tcx> where
        F: FnOnce(u32) -> ty::InferTy,
    {
        if let Some(ty) = opt_ty {
            return ty.fold_with(self);
        }

        match self.freshen_map.entry(key) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let index = self.freshen_count;
                self.freshen_count += 1;
                let t = self.infcx.tcx.mk_ty_infer(freshener(index));
                entry.insert(t);
                t
            }
        }
    }
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.infcx.tcx
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        match *r {
            ty::ReLateBound(..) => {
                // leave bound regions alone
                r
            }

            ty::ReStatic |
            ty::ReEarlyBound(..) |
            ty::ReFree(_) |
            ty::ReScope(_) |
            ty::ReVar(_) |
            ty::RePlaceholder(..) |
            ty::ReEmpty |
            ty::ReErased => {
                // replace all free regions with 'erased
                self.tcx().lifetimes.re_erased
            }

            ty::ReClosureBound(..) => {
                bug!(
                    "encountered unexpected region: {:?}",
                    r,
                );
            }
        }
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if !t.needs_infer() && !t.has_erasable_regions() &&
            !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
            return t;
        }

        let tcx = self.infcx.tcx;

        match t.sty {
            ty::Infer(ty::TyVar(v)) => {
                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
                self.freshen(
                    opt_ty,
                    ty::TyVar(v),
                    ty::FreshTy)
            }

            ty::Infer(ty::IntVar(v)) => {
                self.freshen(
                    self.infcx.int_unification_table.borrow_mut()
                                                    .probe_value(v)
                                                    .map(|v| v.to_type(tcx)),
                    ty::IntVar(v),
                    ty::FreshIntTy)
            }

            ty::Infer(ty::FloatVar(v)) => {
                self.freshen(
                    self.infcx.float_unification_table.borrow_mut()
                                                      .probe_value(v)
                                                      .map(|v| v.to_type(tcx)),
                    ty::FloatVar(v),
                    ty::FreshFloatTy)
            }

            ty::Infer(ty::FreshTy(c)) |
            ty::Infer(ty::FreshIntTy(c)) |
            ty::Infer(ty::FreshFloatTy(c)) => {
                if c >= self.freshen_count {
                    bug!("Encountered a freshend type with id {} \
                          but our counter is only at {}",
                         c,
                         self.freshen_count);
                }
                t
            }

            ty::Generator(..) |
            ty::Bool |
            ty::Char |
            ty::Int(..) |
            ty::Uint(..) |
            ty::Float(..) |
            ty::Adt(..) |
            ty::Str |
            ty::Error |
            ty::Array(..) |
            ty::Slice(..) |
            ty::RawPtr(..) |
            ty::Ref(..) |
            ty::FnDef(..) |
            ty::FnPtr(_) |
            ty::Dynamic(..) |
            ty::Never |
            ty::Tuple(..) |
            ty::Projection(..) |
            ty::UnnormalizedProjection(..) |
            ty::Foreign(..) |
            ty::Param(..) |
            ty::Closure(..) |
            ty::GeneratorWitness(..) |
            ty::Opaque(..) => {
                t.super_fold_with(self)
            }

            ty::Placeholder(..) |
            ty::Bound(..) => bug!("unexpected type {:?}", t),
        }
    }

    fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
        ct // FIXME(const_generics)
    }
}
<commit_msg>impl fold_const for TypeFreshener<commit_after>//! Freshening is the process of replacing unknown variables with fresh types. The idea is that
//! the type, after freshening, contains no inference variables but instead contains either a
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
//!
//! Freshening is used primarily to get a good type for inserting into a cache. The result
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
//!
//! To handle closures, freshened types also have to contain the signature and kind of any
//! closure in the local inference context, as otherwise the cache key might be invalidated.
//! The way this is done is somewhat hacky - the closure signature is appended to the substs,
//! as well as the closure kind "encoded" as a type. Also, special handling is needed when
//! the closure signature contains a reference to the original closure.
//!
//! Note that you should be careful not to allow the output of freshening to leak to the user in
//! error messages or in any other form. Freshening is only really useful as an internal detail.
//!
//! Because of the manipulation required to handle closures, doing arbitrary operations on
//! freshened types is not recommended. However, in addition to doing equality/hash
//! comparisons (for caching), it is possible to do a `ty::_match` operation between
//! 2 freshened types - this works even with the closure encoding.
//!
//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
//! account when making type-overloaded decisions. This is important because of the design of the
//! region inferencer, which is not based on unification but rather on accumulating and then
//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
//! inferencer knows "so far".

use crate::mir::interpret::ConstValue;
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::fold::TypeFolder;
use crate::util::nodemap::FxHashMap;

use std::collections::hash_map::Entry;

use super::InferCtxt;
use super::unify_key::ToType;

pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
    ty_freshen_count: u32,
    const_freshen_count: u32,
    ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
    const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::LazyConst<'tcx>>,
}

impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
               -> TypeFreshener<'a, 'gcx, 'tcx> {
        TypeFreshener {
            infcx,
            ty_freshen_count: 0,
            const_freshen_count: 0,
            ty_freshen_map: Default::default(),
            const_freshen_map: Default::default(),
        }
    }

    fn freshen_ty<F>(
        &mut self,
        opt_ty: Option<Ty<'tcx>>,
        key: ty::InferTy,
        freshener: F,
    ) -> Ty<'tcx>
    where
        F: FnOnce(u32) -> ty::InferTy,
    {
        if let Some(ty) = opt_ty {
            return ty.fold_with(self);
        }

        match self.ty_freshen_map.entry(key) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let index = self.ty_freshen_count;
                self.ty_freshen_count += 1;
                let t = self.infcx.tcx.mk_ty_infer(freshener(index));
                entry.insert(t);
                t
            }
        }
    }

    fn freshen_const<F>(
        &mut self,
        opt_ct: Option<&'tcx ty::LazyConst<'tcx>>,
        key: ty::InferConst<'tcx>,
        freshener: F,
        ty: Ty<'tcx>,
    ) -> &'tcx ty::LazyConst<'tcx>
    where
        F: FnOnce(u32) -> ty::InferConst<'tcx>,
    {
        if let Some(ct) = opt_ct {
            return ct.fold_with(self);
        }

        match self.const_freshen_map.entry(key) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let index = self.const_freshen_count;
                self.const_freshen_count += 1;
                let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty);
                entry.insert(ct);
                ct
            }
        }
    }
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.infcx.tcx
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        match *r {
            ty::ReLateBound(..) => {
                // leave bound regions alone
                r
            }

            ty::ReStatic |
            ty::ReEarlyBound(..) |
            ty::ReFree(_) |
            ty::ReScope(_) |
            ty::ReVar(_) |
            ty::RePlaceholder(..) |
            ty::ReEmpty |
            ty::ReErased => {
                // replace all free regions with 'erased
                self.tcx().lifetimes.re_erased
            }

            ty::ReClosureBound(..) => {
                bug!(
                    "encountered unexpected region: {:?}",
                    r,
                );
            }
        }
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if !t.needs_infer() && !t.has_erasable_regions() &&
            !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
            return t;
        }

        let tcx = self.infcx.tcx;

        match t.sty {
            ty::Infer(ty::TyVar(v)) => {
                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
                self.freshen_ty(
                    opt_ty,
                    ty::TyVar(v),
                    ty::FreshTy)
            }

            ty::Infer(ty::IntVar(v)) => {
                self.freshen_ty(
                    self.infcx.int_unification_table.borrow_mut()
                                                    .probe_value(v)
                                                    .map(|v| v.to_type(tcx)),
                    ty::IntVar(v),
                    ty::FreshIntTy)
            }

            ty::Infer(ty::FloatVar(v)) => {
                self.freshen_ty(
                    self.infcx.float_unification_table.borrow_mut()
                                                      .probe_value(v)
                                                      .map(|v| v.to_type(tcx)),
                    ty::FloatVar(v),
                    ty::FreshFloatTy)
            }

            ty::Infer(ty::FreshTy(ct)) |
            ty::Infer(ty::FreshIntTy(ct)) |
            ty::Infer(ty::FreshFloatTy(ct)) => {
                if ct >= self.ty_freshen_count {
                    bug!("Encountered a freshend type with id {} \
                          but our counter is only at {}",
                         ct,
                         self.ty_freshen_count);
                }
                t
            }

            ty::Generator(..) |
            ty::Bool |
            ty::Char |
            ty::Int(..) |
            ty::Uint(..) |
            ty::Float(..) |
            ty::Adt(..) |
            ty::Str |
            ty::Error |
            ty::Array(..) |
            ty::Slice(..) |
            ty::RawPtr(..) |
            ty::Ref(..) |
            ty::FnDef(..) |
            ty::FnPtr(_) |
            ty::Dynamic(..) |
            ty::Never |
            ty::Tuple(..) |
            ty::Projection(..) |
            ty::UnnormalizedProjection(..) |
            ty::Foreign(..) |
            ty::Param(..) |
            ty::Closure(..) |
            ty::GeneratorWitness(..) |
            ty::Opaque(..) => {
                t.super_fold_with(self)
            }

            ty::Placeholder(..) |
            ty::Bound(..) => bug!("unexpected type {:?}", t),
        }
    }

    fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
        if let ty::LazyConst::Evaluated(ty::Const{ val, ty }) = ct {
            match val {
                ConstValue::Infer(ty::InferConst::Var(v)) => {
                    let opt_ct = self.infcx.const_unification_table
                        .borrow_mut()
                        .probe(*v)
                        .known();
                    return self.freshen_const(
                        opt_ct,
                        ty::InferConst::Var(*v),
                        ty::InferConst::Fresh,
                        ty,
                    );
                }
                ConstValue::Infer(ty::InferConst::Fresh(i)) => {
                    if *i >= self.const_freshen_count {
                        bug!(
                            "Encountered a freshend const with id {} \
                                but our counter is only at {}",
                            i,
                            self.const_freshen_count,
                        );
                    }
                    return ct;
                }

                ConstValue::Infer(ty::InferConst::Canonical(..)) => {
                    bug!("unexpected const {:?}", ct)
                }

                ConstValue::Param(_) |
                ConstValue::Scalar(_) |
                ConstValue::Slice(..) |
                ConstValue::ByRef(..) => {}
            }
        }

        ct.super_fold_with(self)
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap,HashSet};

use std::iter::FromIterator;
use openssl::x509::X509;
use openssl::hash::MessageDigest;

use sozu::messages::{CertFingerprint,CertificateAndKey,Order,HttpFront,TlsFront,Instance};

pub type AppId = String;

#[derive(Debug,Clone,PartialEq,Eq, Serialize, Deserialize)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<HttpFront>>,
  instances:  HashMap<AppId, Vec<Instance>>,
}

#[derive(Debug,Clone,PartialEq,Eq,Serialize, Deserialize)]
pub struct TlsProxy {
  ip_address:   String,
  port:         u16,
  certificates: HashMap<CertFingerprint, CertificateAndKey>,
  fronts:       HashMap<AppId, Vec<TlsFront>>,
  instances:    HashMap<AppId, Vec<Instance>>,
}

#[derive(Debug,Default,Clone,PartialEq,Eq,Serialize,Deserialize)]
pub struct ConfigState {
  instances: HashMap<AppId, Vec<Instance>>,
  http_fronts: HashMap<AppId, Vec<HttpFront>>,
  https_fronts: HashMap<AppId, Vec<TlsFront>>,
  certificates: HashMap<CertFingerprint, CertificateAndKey>,
  //ip, port
  http_addresses: Vec<(String, u16)>,
  https_addresses: Vec<(String, u16)>,
  //tcp:
}

impl ConfigState {
  pub fn add_http_address(&mut self, ip_address: String, port: u16) {
    self.http_addresses.push((ip_address, port))
  }

  pub fn add_https_address(&mut self, ip_address: String, port: u16) {
    self.https_addresses.push((ip_address, port))
  }

  pub fn handle_order(&mut self, order: &Order) {
    match order {
      &Order::AddHttpFront(ref front) => {
        let f = HttpFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        };
        if self.http_fronts.contains_key(&front.app_id) {
          self.http_fronts.get_mut(&front.app_id).map(|front| {
            if !front.contains(&f) {
              front.push(f);
            }
          });
        } else {
          self.http_fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Order::RemoveHttpFront(ref front) => {
        if let Some(front_list) = self.http_fronts.get_mut(&front.app_id) {
          front_list.retain(|el| el.hostname != front.hostname || el.path_begin != front.path_begin);
        }
      },
      &Order::AddCertificate(ref certificate_and_key) => {
        let f = CertificateAndKey {
          certificate:       certificate_and_key.certificate.clone(),
          certificate_chain: certificate_and_key.certificate_chain.clone(),
          key:               certificate_and_key.key.clone(),
        };
        let fingerprint = match X509::from_pem(&certificate_and_key.certificate.as_bytes()[..]).and_then(|cert|
                                  cert.fingerprint(MessageDigest::sha256())) {
          Ok(f)  => f,
          Err(e) => {
            error!("cannot obtain the certificate's fingerprint: {:?}", e);
            return;
          }
        };

        if !self.certificates.contains_key(&fingerprint) {
          self.certificates.insert(fingerprint.clone(), f);
        }
      },
      &Order::RemoveCertificate(ref fingerprint) => {
        self.certificates.remove(fingerprint);
      },
      &Order::AddTlsFront(ref front) => {
        let f = TlsFront {
          app_id:      front.app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          fingerprint: front.fingerprint.clone(),
        };
        if self.https_fronts.contains_key(&front.app_id) {
          self.https_fronts.get_mut(&front.app_id).map(|front| {
            if !front.contains(&f) {
              front.push(f);
            }
          });
        } else {
          self.https_fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Order::RemoveTlsFront(ref front) => {
        self.https_fronts.remove(&front.app_id);
      },
      &Order::AddInstance(ref instance)  => {
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).map(|instance_vec| {
            if !instance_vec.contains(&instance) {
              instance_vec.push(instance.clone());
            }
          });
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(instance.clone()));
        }
      },
      &Order::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
        }
      }
      _ => {}
    }
  }

  pub fn generate_orders(&self) -> Vec<Order> {
    let mut v = Vec::new();
    for (app_id, front_list) in self.http_fronts.iter() {
      for front in front_list {
        v.push(Order::AddHttpFront(HttpFront {
          app_id:     app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        }));
      }
    }

    let mut v = Vec::new();
    for certificate_and_key in (&self.certificates).values() {
      v.push(Order::AddCertificate(certificate_and_key.clone()));
    }

    for (app_id, front_list) in &self.https_fronts {
      for front in front_list {
        v.push(Order::AddTlsFront(TlsFront {
          app_id:      app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          fingerprint: front.fingerprint.clone(),
        }));
      }
    }

    for instance_list in self.instances.values() {
      for instance in instance_list {
        v.push(Order::AddInstance(instance.clone()));
      }
    }

    v
  }

  pub fn diff(&self, other:&ConfigState) -> Vec<Order> {
    let mut my_fronts: HashSet<(&AppId, &HttpFront)> = HashSet::new();
    for (ref app_id, ref front_list) in self.http_fronts.iter() {
      for ref front in front_list.iter() {
        my_fronts.insert((&app_id, &front));
      }
    }
    let mut their_fronts: HashSet<(&AppId, &HttpFront)> = HashSet::new();
    for (ref app_id, ref front_list) in other.http_fronts.iter() {
      for ref front in front_list.iter() {
        their_fronts.insert((&app_id, &front));
      }
    }

    let removed_http_fronts = my_fronts.difference(&their_fronts);
    let added_http_fronts   = their_fronts.difference(&my_fronts);

    let mut my_fronts: HashSet<(&AppId, &TlsFront)> = HashSet::new();
    for (ref app_id, ref front_list) in self.https_fronts.iter() {
      for ref front in front_list.iter() {
        my_fronts.insert((&app_id, &front));
      }
    }
    let mut their_fronts: HashSet<(&AppId, &TlsFront)> = HashSet::new();
    for (ref app_id, ref front_list) in other.https_fronts.iter() {
      for ref front in front_list.iter() {
        their_fronts.insert((&app_id, &front));
      }
    }

    let removed_https_fronts = my_fronts.difference(&their_fronts);
    let added_https_fronts   = their_fronts.difference(&my_fronts);

    let mut my_instances: HashSet<(&AppId, &Instance)> = HashSet::new();
    for (ref app_id, ref instance_list) in self.instances.iter() {
      for ref instance in instance_list.iter() {
        my_instances.insert((&app_id, &instance));
      }
    }
    let mut their_instances: HashSet<(&AppId, &Instance)> = HashSet::new();
    for (ref app_id, ref instance_list) in other.instances.iter() {
      for ref instance in instance_list.iter() {
        their_instances.insert((&app_id, &instance));
      }
    }

    let removed_instances = my_instances.difference(&their_instances);
    let added_instances   = their_instances.difference(&my_instances);

    let my_certificates:    HashSet<(&CertFingerprint, &CertificateAndKey)> = HashSet::from_iter(self.certificates.iter());
    let their_certificates: HashSet<(&CertFingerprint, &CertificateAndKey)> = HashSet::from_iter(other.certificates.iter());

    let removed_certificates = my_certificates.difference(&their_certificates);
    let added_certificates   = their_certificates.difference(&my_certificates);

    let mut v = vec!();

    for &(_, certificate_and_key) in added_certificates {
      v.push(Order::AddCertificate(certificate_and_key.clone()));
    }

    for &(app_id, front) in removed_http_fronts {
     v.push(Order::RemoveHttpFront(HttpFront {
       app_id:     app_id.clone(),
       hostname:   front.hostname.clone(),
       path_begin: front.path_begin.clone(),
      }));
    }

    for &(app_id, front) in removed_https_fronts {
     v.push(Order::RemoveTlsFront(TlsFront {
       app_id:      app_id.clone(),
       hostname:    front.hostname.clone(),
       path_begin:  front.path_begin.clone(),
       fingerprint: front.fingerprint.clone(),
      }));
    }

    for &(_, instance) in added_instances {
      v.push(Order::AddInstance(instance.clone()));
    }

    for &(_, instance) in removed_instances {
      v.push(Order::RemoveInstance(instance.clone()));
    }

    for &(app_id, front) in added_http_fronts {
      v.push(Order::AddHttpFront(HttpFront {
        app_id:     app_id.clone(),
        hostname:   front.hostname.clone(),
        path_begin: front.path_begin.clone(),
      }));
    }

    for &(app_id, front) in added_https_fronts {
      v.push(Order::AddTlsFront(TlsFront {
        app_id:      app_id.clone(),
        hostname:    front.hostname.clone(),
        path_begin:  front.path_begin.clone(),
        fingerprint: front.fingerprint.clone(),
      }));
    }

    for  &(fingerprint, _) in removed_certificates {
      v.push(Order::RemoveCertificate(fingerprint.clone()));
    }
    v
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use sozu::messages::{Order,HttpFront,Instance};

  #[test]
  fn serialize() {
    let mut state:ConfigState = Default::default();
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_order(&Order::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    /*
    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert_eq!(new_state, Some(state));
    */
    //assert!(false);
  }

  #[test]
  fn diff() {
    let mut state:ConfigState = Default::default();
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));

    let mut state2:ConfigState = Default::default();
    state2.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1028 }));

   let e = vec!(
     Order::RemoveHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }),
     Order::RemoveInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }),
     Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1028 }),
   );
   let expected_diff:HashSet<&Order> = HashSet::from_iter(e.iter());

   let d = state.diff(&state2);
   let diff = HashSet::from_iter(d.iter());
   println!("diff orders:\n{:?}\n", diff);
   println!("expected diff orders:\n{:?}\n", expected_diff);

   assert_eq!(diff, expected_diff);
  }
}
<commit_msg>HTTP front commands were not generated<commit_after>use std::collections::{HashMap,HashSet};

use std::iter::FromIterator;
use openssl::x509::X509;
use openssl::hash::MessageDigest;

use sozu::messages::{CertFingerprint,CertificateAndKey,Order,HttpFront,TlsFront,Instance};

pub type AppId = String;

#[derive(Debug,Clone,PartialEq,Eq, Serialize, Deserialize)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<HttpFront>>,
  instances:  HashMap<AppId, Vec<Instance>>,
}

#[derive(Debug,Clone,PartialEq,Eq,Serialize, Deserialize)]
pub struct TlsProxy {
  ip_address:   String,
  port:         u16,
  certificates: HashMap<CertFingerprint, CertificateAndKey>,
  fronts:       HashMap<AppId, Vec<TlsFront>>,
  instances:    HashMap<AppId, Vec<Instance>>,
}

#[derive(Debug,Default,Clone,PartialEq,Eq,Serialize,Deserialize)]
pub struct ConfigState {
  instances: HashMap<AppId, Vec<Instance>>,
  http_fronts: HashMap<AppId, Vec<HttpFront>>,
  https_fronts: HashMap<AppId, Vec<TlsFront>>,
  certificates: HashMap<CertFingerprint, CertificateAndKey>,
  //ip, port
  http_addresses: Vec<(String, u16)>,
  https_addresses: Vec<(String, u16)>,
  //tcp:
}

impl ConfigState {
  pub fn add_http_address(&mut self, ip_address: String, port: u16) {
    self.http_addresses.push((ip_address, port))
  }

  pub fn add_https_address(&mut self, ip_address: String, port: u16) {
    self.https_addresses.push((ip_address, port))
  }

  pub fn handle_order(&mut self, order: &Order) {
    match order {
      &Order::AddHttpFront(ref front) => {
        let f = HttpFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        };
        if self.http_fronts.contains_key(&front.app_id) {
          self.http_fronts.get_mut(&front.app_id).map(|front| {
            if !front.contains(&f) {
              front.push(f);
            }
          });
        } else {
          self.http_fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Order::RemoveHttpFront(ref front) => {
        if let Some(front_list) = self.http_fronts.get_mut(&front.app_id) {
          front_list.retain(|el| el.hostname != front.hostname || el.path_begin != front.path_begin);
        }
      },
      &Order::AddCertificate(ref certificate_and_key) => {
        let f = CertificateAndKey {
          certificate:       certificate_and_key.certificate.clone(),
          certificate_chain: certificate_and_key.certificate_chain.clone(),
          key:               certificate_and_key.key.clone(),
        };
        let fingerprint = match X509::from_pem(&certificate_and_key.certificate.as_bytes()[..]).and_then(|cert|
                                  cert.fingerprint(MessageDigest::sha256())) {
          Ok(f)  => f,
          Err(e) => {
            error!("cannot obtain the certificate's fingerprint: {:?}", e);
            return;
          }
        };

        if !self.certificates.contains_key(&fingerprint) {
          self.certificates.insert(fingerprint.clone(), f);
        }
      },
      &Order::RemoveCertificate(ref fingerprint) => {
        self.certificates.remove(fingerprint);
      },
      &Order::AddTlsFront(ref front) => {
        let f = TlsFront {
          app_id:      front.app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          fingerprint: front.fingerprint.clone(),
        };
        if self.https_fronts.contains_key(&front.app_id) {
          self.https_fronts.get_mut(&front.app_id).map(|front| {
            if !front.contains(&f) {
              front.push(f);
            }
          });
        } else {
          self.https_fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Order::RemoveTlsFront(ref front) => {
        self.https_fronts.remove(&front.app_id);
      },
      &Order::AddInstance(ref instance)  => {
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).map(|instance_vec| {
            if !instance_vec.contains(&instance) {
              instance_vec.push(instance.clone());
            }
          });
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(instance.clone()));
        }
      },
      &Order::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
        }
      }
      _ => {}
    }
  }

  pub fn generate_orders(&self) -> Vec<Order> {
    let mut v = Vec::new();
    for (app_id, front_list) in self.http_fronts.iter() {
      for front in front_list {
        v.push(Order::AddHttpFront(HttpFront {
          app_id:     app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        }));
      }
    }

    for certificate_and_key in (&self.certificates).values() {
      v.push(Order::AddCertificate(certificate_and_key.clone()));
    }

    for (app_id, front_list) in &self.https_fronts {
      for front in front_list {
        v.push(Order::AddTlsFront(TlsFront {
          app_id:      app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          fingerprint: front.fingerprint.clone(),
        }));
      }
    }

    for instance_list in self.instances.values() {
      for instance in instance_list {
        v.push(Order::AddInstance(instance.clone()));
      }
    }

    v
  }

  pub fn diff(&self, other:&ConfigState) -> Vec<Order> {
    let mut my_fronts: HashSet<(&AppId, &HttpFront)> = HashSet::new();
    for (ref app_id, ref front_list) in self.http_fronts.iter() {
      for ref front in front_list.iter() {
        my_fronts.insert((&app_id, &front));
      }
    }
    let mut their_fronts: HashSet<(&AppId, &HttpFront)> = HashSet::new();
    for (ref app_id, ref front_list) in other.http_fronts.iter() {
      for ref front in front_list.iter() {
        their_fronts.insert((&app_id, &front));
      }
    }

    let removed_http_fronts = my_fronts.difference(&their_fronts);
    let added_http_fronts   = their_fronts.difference(&my_fronts);

    let mut my_fronts: HashSet<(&AppId, &TlsFront)> = HashSet::new();
    for (ref app_id, ref front_list) in self.https_fronts.iter() {
      for ref front in front_list.iter() {
        my_fronts.insert((&app_id, &front));
      }
    }
    let mut their_fronts: HashSet<(&AppId, &TlsFront)> = HashSet::new();
    for (ref app_id, ref front_list) in other.https_fronts.iter() {
      for ref front in front_list.iter() {
        their_fronts.insert((&app_id, &front));
      }
    }

    let removed_https_fronts = my_fronts.difference(&their_fronts);
    let added_https_fronts   = their_fronts.difference(&my_fronts);

    let mut my_instances: HashSet<(&AppId, &Instance)> = HashSet::new();
    for (ref app_id, ref instance_list) in self.instances.iter() {
      for ref instance in instance_list.iter() {
        my_instances.insert((&app_id, &instance));
      }
    }
    let mut their_instances: HashSet<(&AppId, &Instance)> = HashSet::new();
    for (ref app_id, ref instance_list) in other.instances.iter() {
      for ref instance in instance_list.iter() {
        their_instances.insert((&app_id, &instance));
      }
    }

    let removed_instances = my_instances.difference(&their_instances);
    let added_instances   = their_instances.difference(&my_instances);

    let my_certificates:    HashSet<(&CertFingerprint, &CertificateAndKey)> = HashSet::from_iter(self.certificates.iter());
    let their_certificates: HashSet<(&CertFingerprint, &CertificateAndKey)> = HashSet::from_iter(other.certificates.iter());

    let removed_certificates = my_certificates.difference(&their_certificates);
    let added_certificates   = their_certificates.difference(&my_certificates);

    let mut v = vec!();

    for &(_, certificate_and_key) in added_certificates {
      v.push(Order::AddCertificate(certificate_and_key.clone()));
    }

    for &(app_id, front) in removed_http_fronts {
     v.push(Order::RemoveHttpFront(HttpFront {
       app_id:     app_id.clone(),
       hostname:   front.hostname.clone(),
       path_begin: front.path_begin.clone(),
      }));
    }

    for &(app_id, front) in removed_https_fronts {
     v.push(Order::RemoveTlsFront(TlsFront {
       app_id:      app_id.clone(),
       hostname:    front.hostname.clone(),
       path_begin:  front.path_begin.clone(),
       fingerprint: front.fingerprint.clone(),
      }));
    }

    for &(_, instance) in added_instances {
      v.push(Order::AddInstance(instance.clone()));
    }

    for &(_, instance) in removed_instances {
      v.push(Order::RemoveInstance(instance.clone()));
    }

    for &(app_id, front) in added_http_fronts {
      v.push(Order::AddHttpFront(HttpFront {
        app_id:     app_id.clone(),
        hostname:   front.hostname.clone(),
        path_begin: front.path_begin.clone(),
      }));
    }

    for &(app_id, front) in added_https_fronts {
      v.push(Order::AddTlsFront(TlsFront {
        app_id:      app_id.clone(),
        hostname:    front.hostname.clone(),
        path_begin:  front.path_begin.clone(),
        fingerprint: front.fingerprint.clone(),
      }));
    }

    for  &(fingerprint, _) in removed_certificates {
      v.push(Order::RemoveCertificate(fingerprint.clone()));
    }
    v
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use sozu::messages::{Order,HttpFront,Instance};

  #[test]
  fn serialize() {
    let mut state:ConfigState = Default::default();
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_order(&Order::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    /*
    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert_eq!(new_state, Some(state));
    */
    //assert!(false);
  }

  #[test]
  fn diff() {
    let mut state:ConfigState = Default::default();
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));

    let mut state2:ConfigState = Default::default();
    state2.handle_order(&Order::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state2.handle_order(&Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1028 }));

   let e = vec!(
     Order::RemoveHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }),
     Order::RemoveInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }),
     Order::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1028 }),
   );
   let expected_diff:HashSet<&Order> = HashSet::from_iter(e.iter());

   let d = state.diff(&state2);
   let diff = HashSet::from_iter(d.iter());
   println!("diff orders:\n{:?}\n", diff);
   println!("expected diff orders:\n{:?}\n", expected_diff);

   assert_eq!(diff, expected_diff);
  }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }

    #[test]
    fn nth_mersenne_prime_test() {
        assert_eq!(mersenne_utils::nth_mersenne_prime("127"), 4);
        assert_eq!(mersenne_utils::nth_mersenne_prime("9"), 0);
    }

    #[test]
    fn mersenne_test() {
        let mersennes:Vec<Vec<usize>> = mersenne_utils::mersennes();
        assert_eq!(mersennes[0][0], 0);
        assert_eq!(mersennes[0][1], 0);

        assert_eq!(mersennes[2][0], 3);
        assert_eq!(mersennes[2][1], 1);
    }
}<commit_msg>White space?<commit_after>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }

    #[test]
    fn nth_mersenne_prime_test() {
        assert_eq!(mersenne_utils::nth_mersenne_prime("127"), 4);
        assert_eq!(mersenne_utils::nth_mersenne_prime("9"), 0);
    }

    #[test]
    fn mersenne_test() {
        let mersennes:Vec<Vec<usize>> = mersenne_utils::mersennes();
        assert_eq!(mersennes[0][0], 0);
        assert_eq!(mersennes[0][1], 0);

        assert_eq!(mersennes[2][0], 3);
        assert_eq!(mersennes[2][1], 1);
    }
}<|endoftext|>


<commit_before>/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

// Rocket relies on this because they export their own `json!` with a different
// doc comment than ours, and various Rust bugs prevent them from calling our
// `json!` from their `json!` so they call `json_internal!` directly. Check with
// @SergioBenitez before making breaking changes to this macro.
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
    // of the elements.
    //
    // Must be invoked as: json_internal!(@array [] $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done with trailing comma.
    (@array [$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    (@array [$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
    };

    // Next element is `true`.
    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
    };

    // Next element is `false`.
    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
    };

    // Next element is an array.
    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    (@array [$($elems:expr,)*] $last:expr) => {
        json_internal!(@array [$($elems,)* json_internal!($last)])
    };

    // Comma after the most recent element.
    (@array [$($elems:expr),*] , $($rest:tt)*) => {
        json_internal!(@array [$($elems,)*] $($rest)*)
    };

    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an object {...}. Each entry is
    // inserted into the given map variable.
    //
    // Must be invoked as: json_internal!(@object $map () $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done.
    (@object $object:ident ()) => {};

    // Insert the current entry followed by trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_internal!(@object $object () $($rest)*);
    };

    // Insert the last entry without trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    (@object $object:ident ($($key:tt)+) : null $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
    };

    // Next value is `true`.
    (@object $object:ident ($($key:tt)+) : true $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
    };

    // Next value is `false`.
    (@object $object:ident ($($key:tt)+) : false $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
    };

    // Next value is an array.
    (@object $object:ident ($($key:tt)+) : [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    (@object $object:ident ($($key:tt)+) : {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    (@object $object:ident ($($key:tt)+) : $value:expr , $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    (@object $object:ident ($($key:tt)+) : $value:expr) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)));
    };

    // Misplaced colon. Trigger a reasonable error message by failing to match
    // the colon in the recursive call.
    (@object $object:ident () : $($rest:tt)*) => {
        json_internal!(@object $object [:] (:));
    };

    // Found a comma inside a key. Trigger a reasonable error message by failing
    // to match the comma in the recursive call.
    (@object $object:ident ($($key:tt)*) , $($rest:tt)*) => {
        json_internal!(@object $object [,] (,));
    };

    // Key is fully parenthesized. This avoids clippy double_parens false
    // positives because the parenthesization may be necessary here.
    (@object $object:ident () ($key:expr) : $($rest:tt)*) => {
        json_internal!(@object $object ($key) : $($rest)*);
    };

    // Munch a token into the current key.
    (@object $object:ident ($($key:tt)*) $tt:tt $($rest:tt)*) => {
        json_internal!(@object $object ($($key)* $tt) $($rest)*);
    };

    //////////////////////////////////////////////////////////////////////////
    // The main implementation.
    //
    // Must be invoked as: json_internal!($($json)+)
    //////////////////////////////////////////////////////////////////////////

    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_internal!(@array [] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_internal!(@object object () $($tt)+);
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    // Must be below every other rule.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}
<commit_msg>Improve error message when json macro ends after colon<commit_after>/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

// Rocket relies on this because they export their own `json!` with a different
// doc comment than ours, and various Rust bugs prevent them from calling our
// `json!` from their `json!` so they call `json_internal!` directly. Check with
// @SergioBenitez before making breaking changes to this macro.
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
    // of the elements.
    //
    // Must be invoked as: json_internal!(@array [] $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done with trailing comma.
    (@array [$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    (@array [$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
    };

    // Next element is `true`.
    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
    };

    // Next element is `false`.
    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
    };

    // Next element is an array.
    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    (@array [$($elems:expr,)*] $last:expr) => {
        json_internal!(@array [$($elems,)* json_internal!($last)])
    };

    // Comma after the most recent element.
    (@array [$($elems:expr),*] , $($rest:tt)*) => {
        json_internal!(@array [$($elems,)*] $($rest)*)
    };

    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an object {...}. Each entry is
    // inserted into the given map variable.
    //
    // Must be invoked as: json_internal!(@object $map () $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done.
    (@object $object:ident ()) => {};

    // Insert the current entry followed by trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_internal!(@object $object () $($rest)*);
    };

    // Insert the last entry without trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    (@object $object:ident ($($key:tt)+) : null $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
    };

    // Next value is `true`.
    (@object $object:ident ($($key:tt)+) : true $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
    };

    // Next value is `false`.
    (@object $object:ident ($($key:tt)+) : false $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
    };

    // Next value is an array.
    (@object $object:ident ($($key:tt)+) : [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    (@object $object:ident ($($key:tt)+) : {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    (@object $object:ident ($($key:tt)+) : $value:expr , $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    (@object $object:ident ($($key:tt)+) : $value:expr) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)));
    };

    // Missing value for last entry. Trigger a reasonable error message
    // referring to the unexpected end of macro invocation.
    (@object $object:ident ($($key:tt)+) :) => {
        json_internal!();
    };

    // Misplaced colon. Trigger a reasonable error message by failing to match
    // the colon in the recursive call.
    (@object $object:ident () : $($rest:tt)*) => {
        json_internal!(@object $object [:] (:));
    };

    // Found a comma inside a key. Trigger a reasonable error message by failing
    // to match the comma in the recursive call.
    (@object $object:ident ($($key:tt)*) , $($rest:tt)*) => {
        json_internal!(@object $object [,] (,));
    };

    // Key is fully parenthesized. This avoids clippy double_parens false
    // positives because the parenthesization may be necessary here.
    (@object $object:ident () ($key:expr) : $($rest:tt)*) => {
        json_internal!(@object $object ($key) : $($rest)*);
    };

    // Munch a token into the current key.
    (@object $object:ident ($($key:tt)*) $tt:tt $($rest:tt)*) => {
        json_internal!(@object $object ($($key)* $tt) $($rest)*);
    };

    //////////////////////////////////////////////////////////////////////////
    // The main implementation.
    //
    // Must be invoked as: json_internal!($($json)+)
    //////////////////////////////////////////////////////////////////////////

    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_internal!(@array [] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_internal!(@object object () $($tt)+);
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    // Must be below every other rule.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}
<|endoftext|>


<commit_before>use rand::Rng;
use num::Integer;
use calx::{V2};
use geomorph;
use geomorph::{Chunk};
use terrain::TerrainType;

pub fn gen_herringbone<R: Rng>(
    rng: &mut R, spec: &::AreaSpec, set_terrain: |V2<int>, TerrainType|) {
    let chunkref = geomorph::get_cache();
    let chunkbor = chunkref.borrow();
    let chunks = chunkbor.iter().filter(
        |c| c.spec.biome == spec.biome && c.spec.depth <= spec.depth)
        .collect::<Vec<&Chunk>>();

    let edge = chunks.iter().filter(|c| !c.exit && c.connected)
        .map(|&c| c).collect::<Vec<&Chunk>>();
    let inner = chunks.iter().filter(|c| !c.exit)
        .map(|&c| c).collect::<Vec<&Chunk>>();
    let exit = chunks.iter().filter(|c| c.exit)
        .map(|&c| c).collect::<Vec<&Chunk>>();

    assert!(!exit.is_empty(), "No exit chunks found");
    assert!(inner.len() + exit.len() == chunks.len());

    let exit_x = rng.gen_range(-1, 0);
    let exit_y = rng.gen_range(-1, 0);

    for cy in range(-2i, 2) {
        for cx in range(-2i, 2) {
            let on_edge = cy == -2 || cx == -2 || cy == 1 || cx == 1;

            let chunk = rng.choose(
                if (cx, cy) == (exit_x, exit_y) { exit.as_slice() }
                else if on_edge { edge.as_slice() }
                else { inner.as_slice() }).unwrap();

            for (&(x, y), &terrain) in chunk.cells.iter() {
                set_terrain(herringbone_map((cx, cy), (x, y)), terrain);
            }
        }
    }
}

// Map in-chunk coordinates to on-map coordinates based on chunk position in
// the herringbone chunk grid.
fn herringbone_map(chunk_pos: (int, int), in_chunk_pos: (int, int)) -> V2<int> {
    let (cx, cy) = chunk_pos;
    let (div, m) = cx.div_mod_floor(&2);
    let (x, y) = in_chunk_pos;

    let origin_x = div * CHUNK_W + cy * CHUNK_W;
    let origin_y = cy * CHUNK_W - m * CHUNK_W - 3 * div * CHUNK_W;

    if m == 0 {
        V2(origin_x + x, origin_y + y)
    } else {
        V2(origin_x + y, origin_y + x)
    }
}

static CHUNK_W: int = 11;
<commit_msg>Can spawn exit chunk anywhere on map<commit_after>use rand::Rng;
use num::Integer;
use calx::{V2};
use geomorph;
use geomorph::{Chunk};
use terrain::TerrainType;

pub fn gen_herringbone<R: Rng>(
    rng: &mut R, spec: &::AreaSpec, set_terrain: |V2<int>, TerrainType|) {
    let chunkref = geomorph::get_cache();
    let chunkbor = chunkref.borrow();
    let chunks = chunkbor.iter().filter(
        |c| c.spec.biome == spec.biome && c.spec.depth <= spec.depth)
        .collect::<Vec<&Chunk>>();

    let edge = chunks.iter().filter(|c| !c.exit && c.connected)
        .map(|&c| c).collect::<Vec<&Chunk>>();
    let inner = chunks.iter().filter(|c| !c.exit)
        .map(|&c| c).collect::<Vec<&Chunk>>();
    let exit = chunks.iter().filter(|c| c.exit)
        .map(|&c| c).collect::<Vec<&Chunk>>();

    assert!(!exit.is_empty(), "No exit chunks found");
    assert!(inner.len() + exit.len() == chunks.len());

    let exit_x = rng.gen_range(-2, 2);
    let exit_y = rng.gen_range(-2, 2);

    for cy in range(-2i, 2) {
        for cx in range(-2i, 2) {
            let on_edge = cy == -2 || cx == -2 || cy == 1 || cx == 1;

            let chunk = rng.choose(
                if (cx, cy) == (exit_x, exit_y) { exit.as_slice() }
                else if on_edge { edge.as_slice() }
                else { inner.as_slice() }).unwrap();

            for (&(x, y), &terrain) in chunk.cells.iter() {
                set_terrain(herringbone_map((cx, cy), (x, y)), terrain);
            }
        }
    }
}

// Map in-chunk coordinates to on-map coordinates based on chunk position in
// the herringbone chunk grid.
fn herringbone_map(chunk_pos: (int, int), in_chunk_pos: (int, int)) -> V2<int> {
    let (cx, cy) = chunk_pos;
    let (div, m) = cx.div_mod_floor(&2);
    let (x, y) = in_chunk_pos;

    let origin_x = div * CHUNK_W + cy * CHUNK_W;
    let origin_y = cy * CHUNK_W - m * CHUNK_W - 3 * div * CHUNK_W;

    if m == 0 {
        V2(origin_x + x, origin_y + y)
    } else {
        V2(origin_x + y, origin_y + x)
    }
}

static CHUNK_W: int = 11;
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: This file should be auto-generated

pub const ACTION_NONE: i32 = 0;
pub const ACTION_STOP: i32 = 1;
pub const ACTION_BREAK: i32 = 2;
pub const ACTION_RUN: i32 = 3;
pub const ACTION_STEP: i32 = 4;
pub const ACTION_STEP_OUT: i32 = 5;
pub const ACTION_STEP_OVER: i32 = 6;

// Events

pub const EVENT_NONE: i32 = 0;
pub const EVENT_GET_LOCALS: i32 = 1;
pub const EVENT_SET_LOCALS: i32 = 2;
pub const EVENT_GET_CALLSTACK: i32 = 3;
pub const EVENT_SET_CALLSTACK: i32 = 4;
pub const EVENT_GET_WATCH: i32 = 5;
pub const EVENT_SET_WATCH: i32 = 6;
pub const EVENT_GET_REGISTERS: i32 = 7;
pub const EVENT_SET_REGISTERS: i32 = 8;
pub const EVENT_GET_MEMORY: i32 = 9;
pub const EVENT_SET_MEMORY: i32 = 10;
pub const EVENT_GET_TTY: i32 = 11;
pub const EVENT_SET_TTY: i32 = 12;
pub const EVENT_GET_EXCEPTION_LOCATION: i32 = 13;
pub const EVENT_SET_EXCEPTION_LOCATION: i32 = 14;
pub const EVENT_GET_DISASSEMBLY: i32 = 15;
pub const EVENT_SET_DISASSEMBLY: i32 = 16;
pub const EVENT_GET_STATUS: i32 = 17;
pub const EVENT_SET_STATUS: i32 = 18;
pub const EVENT_SET_THREADS: i32 = 19;
pub const EVENT_GET_THREADS: i32 = 20;
pub const EVENT_SELECT_THREAD: i32 = 21;
pub const EVENT_SELECT_FRAME: i32 = 22;
pub const EVENT_GET_SOURCE_FILES: i32 = 23;
pub const EVENT_SET_SOURCE_FILES: i32 = 24;

pub const EVENT_SET_SOURCE_CODE_FILE: i32 = 25;

pub const EVENT_SET_BREAKPOINT: i32 = 26;
pub const EVENT_REPLY_BREAKPOINT: i32 = 27;

pub const EVENT_DELET_EBREAKPOINT: i32 = 28;
pub const EVENT_SET_EXECUTABLE: i32 = 29;
pub const EVENT_ACTION: i32 = 30;
pub const EVENT_ATTACH_TO_PROCESS: i32 = 31;
pub const EVENT_ATTACH_TO_REMOTE_SESSION: i32 = 32;

pub const EVENT_EXECUTE_CONSOLE: i32 = 33;
pub const EVENT_GET_CONSOLE: i32 = 34;

pub const EVENT_MENU_EVENT: i32 = 35;

pub const PDEVENT_TOGGLE_BREAKPOINT_CURRENT_LINE: i32 = 36;

<commit_msg>Fixed typo<commit_after>///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: This file should be auto-generated

pub const ACTION_NONE: i32 = 0;
pub const ACTION_STOP: i32 = 1;
pub const ACTION_BREAK: i32 = 2;
pub const ACTION_RUN: i32 = 3;
pub const ACTION_STEP: i32 = 4;
pub const ACTION_STEP_OUT: i32 = 5;
pub const ACTION_STEP_OVER: i32 = 6;

// Events

pub const EVENT_NONE: i32 = 0;
pub const EVENT_GET_LOCALS: i32 = 1;
pub const EVENT_SET_LOCALS: i32 = 2;
pub const EVENT_GET_CALLSTACK: i32 = 3;
pub const EVENT_SET_CALLSTACK: i32 = 4;
pub const EVENT_GET_WATCH: i32 = 5;
pub const EVENT_SET_WATCH: i32 = 6;
pub const EVENT_GET_REGISTERS: i32 = 7;
pub const EVENT_SET_REGISTERS: i32 = 8;
pub const EVENT_GET_MEMORY: i32 = 9;
pub const EVENT_SET_MEMORY: i32 = 10;
pub const EVENT_GET_TTY: i32 = 11;
pub const EVENT_SET_TTY: i32 = 12;
pub const EVENT_GET_EXCEPTION_LOCATION: i32 = 13;
pub const EVENT_SET_EXCEPTION_LOCATION: i32 = 14;
pub const EVENT_GET_DISASSEMBLY: i32 = 15;
pub const EVENT_SET_DISASSEMBLY: i32 = 16;
pub const EVENT_GET_STATUS: i32 = 17;
pub const EVENT_SET_STATUS: i32 = 18;
pub const EVENT_SET_THREADS: i32 = 19;
pub const EVENT_GET_THREADS: i32 = 20;
pub const EVENT_SELECT_THREAD: i32 = 21;
pub const EVENT_SELECT_FRAME: i32 = 22;
pub const EVENT_GET_SOURCE_FILES: i32 = 23;
pub const EVENT_SET_SOURCE_FILES: i32 = 24;

pub const EVENT_SET_SOURCE_CODE_FILE: i32 = 25;

pub const EVENT_SET_BREAKPOINT: i32 = 26;
pub const EVENT_REPLY_BREAKPOINT: i32 = 27;

pub const EVENT_DELETE_BREAKPOINT: i32 = 28;
pub const EVENT_SET_EXECUTABLE: i32 = 29;
pub const EVENT_ACTION: i32 = 30;
pub const EVENT_ATTACH_TO_PROCESS: i32 = 31;
pub const EVENT_ATTACH_TO_REMOTE_SESSION: i32 = 32;

pub const EVENT_EXECUTE_CONSOLE: i32 = 33;
pub const EVENT_GET_CONSOLE: i32 = 34;

pub const EVENT_MENU_EVENT: i32 = 35;

pub const PDEVENT_TOGGLE_BREAKPOINT_CURRENT_LINE: i32 = 36;

<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};

pub trait Map<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
  pure fn traverse(f: fn((&K), (@Option<V>)));
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

/**
 * A purely functional Red-Black tree.
 *
 * A port of Matt Might's Scala port of Okasaki's RB Trees: http://matt.might.net/articles/implementation-of-immutable-purely-functional-okasaki-red-black-tree-maps-in-scala/RBMap.scala
 * which was itself a port of http://www.ccs.neu.edu/course/cs3500wc/jfp99redblack.pdf
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : Map<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  /// Visit all pairs in the map in order.
  pure fn traverse(f: fn((&K), (@Option<V>))) {
    match *self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.traverse(f);
        f(&key, maybe_value);
        right.traverse(f);
      }
    }
}

  pure fn put(k : K, v : V) -> @RBMap<K, V> {
    self.modifiedWith(k, @Some(v))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modifiedWith(k, @None)
  }

  priv pure fn blacken(n : @RBMap<K, V>) -> @RBMap<K, V> {
    match n {
      @Leaf => n,
      @Tree(_,l,k,v,r) => @Tree(Black,l,k,v,r)
    }
  }

  priv pure fn modifiedWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    self.blacken(self.modWith(k, new_value))
  }

  priv pure fn balance (c : RBColor, l : @RBMap<K,V>, k : K, v : @Option<V>, r : @RBMap<K,V>) -> @RBMap<K,V> {
    match (c,l,k,v,r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,@Tree(Red,a,xK,xV,@Tree(Red,b,yK,yV,c)),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,a,xK,xV,@Tree(Red,@Tree(Red,b,yK,yV,c),zK,zV,d)) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,a,xK,xV,@Tree(Red,b,yK,yV,@Tree(Red,c,zK,zV,d))) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  priv pure fn modWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balance(color, left.modWith(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balance(color, left, key, original_value, right.modWith(k, new_value))
        }
      }
    }
  }
}

#[test]
fn test_rb_tree_create() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 167);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(167));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(167));
}

#[test]
fn test_traverse() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, k: int, _v: Option<int>) {
    assert (*n == k); *n += 1;
  }

  v5.traverse(|x,y| t(n, *x, *y));
}
<commit_msg>renaming Map to PersistentMap, indenting properly<commit_after>use core::cmp::{Eq, Ord};

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
  pure fn traverse(f: fn((&K), (@Option<V>)));
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

/**
 * A purely functional Red-Black tree.
 *
 * A port of Matt Might's Scala port of Okasaki's RB Trees: http://matt.might.net/articles/implementation-of-immutable-purely-functional-okasaki-red-black-tree-maps-in-scala/RBMap.scala
 * which was itself a port of http://www.ccs.neu.edu/course/cs3500wc/jfp99redblack.pdf
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  /// Visit all pairs in the map in order.
  pure fn traverse(f: fn((&K), (@Option<V>))) {
    match *self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.traverse(f);
        f(&key, maybe_value);
        right.traverse(f);
      }
    }
  }

  pure fn put(k : K, v : V) -> @RBMap<K, V> {
    self.modifiedWith(k, @Some(v))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modifiedWith(k, @None)
  }

  priv pure fn blacken(n : @RBMap<K, V>) -> @RBMap<K, V> {
    match n {
      @Leaf => n,
      @Tree(_,l,k,v,r) => @Tree(Black,l,k,v,r)
    }
  }

  priv pure fn modifiedWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    self.blacken(self.modWith(k, new_value))
  }

  priv pure fn balance (c : RBColor, l : @RBMap<K,V>, k : K, v : @Option<V>, r : @RBMap<K,V>) -> @RBMap<K,V> {
    match (c,l,k,v,r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,@Tree(Red,a,xK,xV,@Tree(Red,b,yK,yV,c)),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,a,xK,xV,@Tree(Red,@Tree(Red,b,yK,yV,c),zK,zV,d)) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (Black,a,xK,xV,@Tree(Red,b,yK,yV,@Tree(Red,c,zK,zV,d))) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  priv pure fn modWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balance(color, left.modWith(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balance(color, left, key, original_value, right.modWith(k, new_value))
        }
      }
    }
  }
}

#[test]
fn test_rb_tree_create() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 167);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(167));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(167));
}

#[test]
fn test_traverse() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, k: int, _v: Option<int>) {
    assert (*n == k); *n += 1;
  }

  v5.traverse(|x,y| t(n, *x, *y));
}
<|endoftext|>


<commit_before>#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Range;

use crate::ByteIndex;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
pub struct Span {
    start: ByteIndex,
    end: ByteIndex,
}

impl Span {
    /// Create a new span from a starting and ending span.
    pub fn new(start: impl Into<ByteIndex>, end: impl Into<ByteIndex>) -> Span {
        let start = start.into();
        let end = end.into();

        assert!(end >= start);

        Span { start, end }
    }

    /// Gives an empty span at the start of a source.
    pub const fn initial() -> Span {
        Span {
            start: ByteIndex(0),
            end: ByteIndex(0),
        }
    }

    /// Measure the span of a string.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::from_str("hello");
    ///
    /// assert_eq!(span, Span::new(0, 5));
    /// ```
    pub fn from_str(s: &str) -> Span {
        Span::new(0, s.len() as u32)
    }

    /// Combine two spans by taking the start of the earlier span
    /// and the end of the later span.
    ///
    /// Note: this will work even if the two spans are disjoint.
    /// If this doesn't make sense in your application, you should handle it yourself.
    /// In that case, you can use `Span::disjoint` as a convenience function.
    ///
    /// ```rust
    /// use codespan::Span;
    ///
    /// let span1 = Span::new(0, 4);
    /// let span2 = Span::new(10, 16);
    ///
    /// assert_eq!(Span::merge(span1, span2), Span::new(0, 16));
    /// ```
    pub fn merge(self, other: Span) -> Span {
        use std::cmp::{max, min};

        let start = min(self.start, other.start);
        let end = max(self.end, other.end);
        Span::new(start, end)
    }

    /// A helper function to tell whether two spans do not overlap.
    ///
    /// ```
    /// use codespan::Span;
    /// let span1 = Span::new(0, 4);
    /// let span2 = Span::new(10, 16);
    /// assert!(span1.disjoint(span2));
    /// ```
    pub fn disjoint(self, other: Span) -> bool {
        let (first, last) = if self.end < other.end {
            (self, other)
        } else {
            (other, self)
        };
        first.end <= last.start
    }
    /// Get the starting byte index.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::new(0, 4);
    ///
    /// assert_eq!(span.start(), ByteIndex::from(0));
    /// ```
    pub fn start(self) -> ByteIndex {
        self.start
    }

    /// Get the ending byte index.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::new(0, 4);
    ///
    /// assert_eq!(span.end(), ByteIndex::from(4));
    /// ```
    pub fn end(self) -> ByteIndex {
        self.end
    }
}

impl Default for Span {
    fn default() -> Span {
        Span::initial()
    }
}

impl fmt::Display for Span {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "[{start}, {end})",
            start = self.start(),
            end = self.end(),
        )
    }
}

impl<I> From<Range<I>> for Span
where
    I: Into<ByteIndex>,
{
    fn from(range: Range<I>) -> Span {
        Span::new(range.start, range.end)
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_merge() {
        use super::Span;

        // overlap
        let a = Span::from(1..5);
        let b = Span::from(3..10);
        assert_eq!(a.merge(b), Span::from(1..10));
        assert_eq!(b.merge(a), Span::from(1..10));

        // subset
        let two_four = (2..4).into();
        assert_eq!(a.merge(two_four), (1..5).into());
        assert_eq!(two_four.merge(a), (1..5).into());

        // disjoint
        let ten_twenty = (10..20).into();
        assert_eq!(a.merge(ten_twenty), (1..20).into());
        assert_eq!(ten_twenty.merge(a), (1..20).into());

        // identity
        assert_eq!(a.merge(a), a);
    }
    #[test]
    fn test_disjoint() {
        use super::Span;

        // overlap
        let a = Span::from(1..5);
        let b = Span::from(3..10);
        assert!(!a.disjoint(b));
        assert!(!b.disjoint(a));

        // subset
        let two_four = (2..4).into();
        assert!(!a.disjoint(two_four));
        assert!(!two_four.disjoint(a));

        // disjoint
        let ten_twenty = (10..20).into();
        assert!(a.disjoint(ten_twenty));
        assert!(ten_twenty.disjoint(a));

        // identity
        assert!(!a.disjoint(a));

        // off by one (upper bound)
        let c = Span::from(5..10);
        assert!(a.disjoint(c));
        assert!(c.disjoint(a));
        // off by one (lower bound)
        let d = Span::from(0..1);
        assert!(a.disjoint(d));
        assert!(d.disjoint(a));
    }
}
<commit_msg>Fix formatting<commit_after>#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Range;

use crate::ByteIndex;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
pub struct Span {
    start: ByteIndex,
    end: ByteIndex,
}

impl Span {
    /// Create a new span from a starting and ending span.
    pub fn new(start: impl Into<ByteIndex>, end: impl Into<ByteIndex>) -> Span {
        let start = start.into();
        let end = end.into();

        assert!(end >= start);

        Span { start, end }
    }

    /// Gives an empty span at the start of a source.
    pub const fn initial() -> Span {
        Span {
            start: ByteIndex(0),
            end: ByteIndex(0),
        }
    }

    /// Measure the span of a string.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::from_str("hello");
    ///
    /// assert_eq!(span, Span::new(0, 5));
    /// ```
    pub fn from_str(s: &str) -> Span {
        Span::new(0, s.len() as u32)
    }

    /// Combine two spans by taking the start of the earlier span
    /// and the end of the later span.
    ///
    /// Note: this will work even if the two spans are disjoint.
    /// If this doesn't make sense in your application, you should handle it yourself.
    /// In that case, you can use `Span::disjoint` as a convenience function.
    ///
    /// ```rust
    /// use codespan::Span;
    ///
    /// let span1 = Span::new(0, 4);
    /// let span2 = Span::new(10, 16);
    ///
    /// assert_eq!(Span::merge(span1, span2), Span::new(0, 16));
    /// ```
    pub fn merge(self, other: Span) -> Span {
        use std::cmp::{max, min};

        let start = min(self.start, other.start);
        let end = max(self.end, other.end);
        Span::new(start, end)
    }

    /// A helper function to tell whether two spans do not overlap.
    ///
    /// ```
    /// use codespan::Span;
    /// let span1 = Span::new(0, 4);
    /// let span2 = Span::new(10, 16);
    /// assert!(span1.disjoint(span2));
    /// ```
    pub fn disjoint(self, other: Span) -> bool {
        let (first, last) = if self.end < other.end {
            (self, other)
        } else {
            (other, self)
        };
        first.end <= last.start
    }

    /// Get the starting byte index.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::new(0, 4);
    ///
    /// assert_eq!(span.start(), ByteIndex::from(0));
    /// ```
    pub fn start(self) -> ByteIndex {
        self.start
    }

    /// Get the ending byte index.
    ///
    /// ```rust
    /// use codespan::{ByteIndex, Span};
    ///
    /// let span = Span::new(0, 4);
    ///
    /// assert_eq!(span.end(), ByteIndex::from(4));
    /// ```
    pub fn end(self) -> ByteIndex {
        self.end
    }
}

impl Default for Span {
    fn default() -> Span {
        Span::initial()
    }
}

impl fmt::Display for Span {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "[{start}, {end})",
            start = self.start(),
            end = self.end(),
        )
    }
}

impl<I> From<Range<I>> for Span
where
    I: Into<ByteIndex>,
{
    fn from(range: Range<I>) -> Span {
        Span::new(range.start, range.end)
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_merge() {
        use super::Span;

        // overlap
        let a = Span::from(1..5);
        let b = Span::from(3..10);
        assert_eq!(a.merge(b), Span::from(1..10));
        assert_eq!(b.merge(a), Span::from(1..10));

        // subset
        let two_four = (2..4).into();
        assert_eq!(a.merge(two_four), (1..5).into());
        assert_eq!(two_four.merge(a), (1..5).into());

        // disjoint
        let ten_twenty = (10..20).into();
        assert_eq!(a.merge(ten_twenty), (1..20).into());
        assert_eq!(ten_twenty.merge(a), (1..20).into());

        // identity
        assert_eq!(a.merge(a), a);
    }
    #[test]
    fn test_disjoint() {
        use super::Span;

        // overlap
        let a = Span::from(1..5);
        let b = Span::from(3..10);
        assert!(!a.disjoint(b));
        assert!(!b.disjoint(a));

        // subset
        let two_four = (2..4).into();
        assert!(!a.disjoint(two_four));
        assert!(!two_four.disjoint(a));

        // disjoint
        let ten_twenty = (10..20).into();
        assert!(a.disjoint(ten_twenty));
        assert!(ten_twenty.disjoint(a));

        // identity
        assert!(!a.disjoint(a));

        // off by one (upper bound)
        let c = Span::from(5..10);
        assert!(a.disjoint(c));
        assert!(c.disjoint(a));
        // off by one (lower bound)
        let d = Span::from(0..1);
        assert!(a.disjoint(d));
        assert!(d.disjoint(a));
    }
}
<|endoftext|>