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

// TODO check whether hashes in rust vary by CPU endianness?
#[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SiphashID {
  data: [u64; 2],
}
pub struct SiphashID_Generator {
  data: [SipHasher; 2],
}
impl Hasher for SiphashID_Generator {
  fn finish(&self) -> u64 {
    panic!()
  }//Hack: this is actually for generating SiphashID, not 64-bit
  fn write(&mut self, bytes: &[u8]) {
    self.data[0].write(bytes);
    self.data[1].write(bytes);
  }
  // TODO: should we implement the others for efficiency?
}
impl SiphashID_Generator {
  fn generate(&self) -> SiphashID {
    SiphashID { data: [self.data[0].finish(), self.data[1].finish()] }
  }
  fn new() -> SiphashID_Generator {
    SiphashID_Generator { data: [SipHasher::new(), SipHasher::new()] }
  }
}
// other possible names: hash_up_a_siphash_id?
fn collision_resistant_hash<T: Hash>(data: &T) -> SiphashID {
  let mut s = SiphashID_Generator::new();
  data.hash(&mut s);
  s.generate()
}

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

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

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

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

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

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

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

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

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

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

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

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

fn beginning_of_moment<Base: BaseTime>(base_time: Base) -> GenericExtendedTime<Base> {
  GenericExtendedTime {
    base: base_time,
    iteration: 0,
    id: SiphashID { data: [0, 0] },
  }
}
// predictor_idx is zero-based
fn extended_time_of_predicted_event<Base: BaseTime>(predictor_idx: u32,
                                       entity_id: SiphashID,
                                       event_base_time: Base,
                                       when_event_was_predicted: &GenericExtendedTime<Base>)
                                       -> Option<GenericExtendedTime<Base>> {
  let id = collision_resistant_hash(&(predictor_idx, entity_id));
  let iteration = match event_base_time.cmp(&when_event_was_predicted.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => 0,
    Ordering::Equal => {
      if id > when_event_was_predicted.id {
        when_event_was_predicted.iteration
      } else {
        when_event_was_predicted.iteration + 1
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    id: id,
    iteration: iteration,
  })
}

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

// Note: in the future, we expect we might use a custom hash table type that knows it can rely on SiphashID to already be random, so we don't need to hash it again. This also applies to FieldID, although there may be some complications in that case.
impl Hash for SiphashID {
  fn hash<H: Hasher>(&self, state: &mut H) {
    self.data[0].hash(state);
  }
}
impl<Base: BaseTime> Hash for GenericExtendedTime<Base> {
  fn hash<H: Hasher>(&self, state: &mut H) {
    self.id.hash(state);
  }
}

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

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

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

pub enum FiatEventOperationResult {
  Success,
  InvalidInput,
  InvalidTime,
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

type Event<M> = Rc<for<'d> Fn(&'d mut M)>;
#[derive (Clone)]
enum Prediction<B: Basics, E> {
  Nothing,
  Immediately(E),
  At(B::Time, E),
}
type Predictor<B: Basics, M: Mutator<B>, PA: PredictorAccessor<B>> =
  Rc<for<'b, 'c> Fn(&'b mut PA, SiphashID) -> Prediction<B, Event<M>>>;

mod inefficient_flat_time_steward;
// mod simple_flat_time_steward;

#[test]
fn it_works() {}
<commit_msg>improve hashing a bit (discussed with eli)<commit_after>use std::hash::{Hash, Hasher, SipHasher};
use std::any::Any;
use std::rc::Rc;
use std::cmp::Ordering;

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

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

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

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

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

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

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

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

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

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

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

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

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

fn beginning_of_moment<Base: BaseTime>(base_time: Base) -> GenericExtendedTime<Base> {
  GenericExtendedTime {
    base: base_time,
    iteration: 0,
    id: SiphashID { data: [0, 0] },
  }
}
// predictor_idx is zero-based
fn extended_time_of_predicted_event<Base: BaseTime>(predictor_idx: u32,
                                       entity_id: SiphashID,
                                       event_base_time: Base,
                                       when_event_was_predicted: &GenericExtendedTime<Base>)
                                       -> Option<GenericExtendedTime<Base>> {
  let id = collision_resistant_hash(&(predictor_idx, entity_id));
  let iteration = match event_base_time.cmp(&when_event_was_predicted.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => 0,
    Ordering::Equal => {
      if id > when_event_was_predicted.id {
        when_event_was_predicted.iteration
      } else {
        when_event_was_predicted.iteration + 1
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    id: id,
    iteration: iteration,
  })
}

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

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

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

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

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

pub enum FiatEventOperationResult {
  Success,
  InvalidInput,
  InvalidTime,
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

type Event<M> = Rc<for<'d> Fn(&'d mut M)>;
#[derive (Clone)]
enum Prediction<B: Basics, E> {
  Nothing,
  Immediately(E),
  At(B::Time, E),
}
type Predictor<B: Basics, M: Mutator<B>, PA: PredictorAccessor<B>> =
  Rc<for<'b, 'c> Fn(&'b mut PA, SiphashID) -> Prediction<B, Event<M>>>;

mod inefficient_flat_time_steward;
// mod simple_flat_time_steward;

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


<commit_before>extern "C" {
    #![allow(improper_ctypes)] // we do not actually cross the FFI bound here

    fn rust_fuzzer_test_input(input: &[u8]);
}

#[export_name="LLVMFuzzerTestOneInput"]
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
    ::std::panic::catch_unwind(|| unsafe {
        let data_slice = ::std::slice::from_raw_parts(data, size);
        rust_fuzzer_test_input(data_slice);
    }).err().map(|_| ::std::process::abort());
    0
}

#[macro_export]
macro_rules! fuzz_target {
    (|$bytes:ident| $body:block) => {
        #[no_mangle]
        pub extern fn rust_fuzzer_test_input($bytes: &[u8]) {
            $body
        }
    };
    (|$data:ident: &[u8]| $body:block) => {
        fuzz_target!(|$data| $body);
    };
    (|$data:ident: $dty: ty| $body:block) => {
        extern crate arbitrary;

        #[no_mangle]
        pub extern fn rust_fuzzer_test_input(bytes: &[u8]) {
            use arbitrary::{Arbitrary, RingBuffer};

            let $data: $dty = if let Ok(d) = RingBuffer::new(bytes, bytes.len()).and_then(|mut b|{
                Arbitrary::arbitrary(&mut b).map_err(|_| "")
            }) {
                d
            } else {
                return
            };
            $body
        }
    };
}
<commit_msg>Register a custom panic hook calling process::abort()<commit_after>extern "C" {
    #![allow(improper_ctypes)] // we do not actually cross the FFI bound here

    fn rust_fuzzer_test_input(input: &[u8]);
}

#[export_name="LLVMFuzzerTestOneInput"]
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
    ::std::panic::catch_unwind(|| unsafe {
        let data_slice = ::std::slice::from_raw_parts(data, size);
        rust_fuzzer_test_input(data_slice);
    })
    .err().map(|_|
        // hopefully the custom panic hook will be called before and abort the
        // process before the stack frames are unwinded.
        ::std::process::abort()
    );
    0
}

#[export_name="LLVMFuzzerInitialize"]
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
    // Registers a panic hook that aborts the process before unwinding.
    // It is useful to abort before unwinding so that the fuzzer will then be
    // able to analyse the process stack frames to tell different bugs appart.
    ::std::panic::set_hook(Box::new(|_| {
            ::std::process::abort();
    }));
    0
}

#[macro_export]
macro_rules! fuzz_target {
    (|$bytes:ident| $body:block) => {
        #[no_mangle]
        pub extern fn rust_fuzzer_test_input($bytes: &[u8]) {
            $body
        }
    };
    (|$data:ident: &[u8]| $body:block) => {
        fuzz_target!(|$data| $body);
    };
    (|$data:ident: $dty: ty| $body:block) => {
        extern crate arbitrary;

        #[no_mangle]
        pub extern fn rust_fuzzer_test_input(bytes: &[u8]) {
            use arbitrary::{Arbitrary, RingBuffer};

            let $data: $dty = if let Ok(d) = RingBuffer::new(bytes, bytes.len()).and_then(|mut b|{
                Arbitrary::arbitrary(&mut b).map_err(|_| "")
            }) {
                d
            } else {
                return
            };
            $body
        }
    };
}
<|endoftext|>


<commit_before>//! Micro-library for converting from geodetic to UTM coordinates.

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

pub struct Ellipsoid {
    a: f64,
    f: f64,
}

const WGS84: Ellipsoid = Ellipsoid {
    a: 6378137.0,
    f: 1.0 / 298.257222101,
};

/// Converts a latitude and longitude in decimal degrees to UTM coordinates using the WGS84 ellipsoid.
///
/// # Examples
///
/// ```
/// use utm::to_utm_wgs84;
/// let (northing, easting, meridian_convergence) = to_utm_wgs84(40.62, -123.45, 10);
/// ```
pub fn to_utm_wgs84(latitude: f64, longitude: f64, zone: u8) -> (f64, f64, f64) {
    let latitude = latitude * PI / 180.0;
    let longitude = longitude * PI / 180.0;
    radians_to_utm_wgs64(latitude, longitude, zone)
}

/// Converts a latitude and longitude in radians to UTM coordinates using the WGS84 ellipsoid.
///
/// # Examples
///
/// ```
/// use std::f64::consts::PI;
/// use utm::to_utm_wgs84;
/// let latitude = 40.62 * PI / 180.0;
/// let longitude = -123.45 * PI / 180.0;
/// let (northing, easting, meridian_convergence) = to_utm_wgs84(latitude, longitude, 10);
/// ```
pub fn radians_to_utm_wgs64(latitude: f64, longitude: f64, zone: u8) -> (f64, f64, f64) {
    let ellipsoid = WGS84;
    let long_origin = zone as f64 * 6.0 - 183.0;
    let e2 = 2.0 * ellipsoid.f - ellipsoid.f * ellipsoid.f;
    let ep2 = e2 / (1.0 - e2);

    let n = ellipsoid.a / (1.0 - e2 * latitude.sin() * latitude.sin()).sqrt();
    let t = latitude.tan() * latitude.tan();
    let c = ep2 * latitude.cos() * latitude.cos();
    let a = latitude.cos() * (longitude - (long_origin * PI / 180.0));

    let term1 = 1.0 - e2 / 4.0 - (3.0 * e2 * e2) / 64.0 - (5.0 * e2 * e2 * e2) / 256.0;
    let term2 = (3.0 * e2) / 8.0 + (3.0 * e2 * e2) / 32.0 + (45.0 * e2 * e2 * e2) / 1024.0;
    let term3 = (15.0 * e2 * e2) / 256.0 + (45.0 * e2 * e2 * e2) / 1024.0;
    let term4 = (35.0 * e2 * e2 * e2) / 3072.0;

    let m = ellipsoid.a *
            (term1 * latitude - term2 * (2.0 * latitude).sin() + term3 * (4.0 * latitude).sin() -
             term4 * (6.0 * latitude).sin());

    let x1 = ((1.0 - t + c) * a * a * a) / 6.0;
    let x2 = ((5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ep2) * a * a * a * a * a) / 120.0;
    let x = 0.9996 * n * (a + x1 + x2);

    let y1 = (5.0 - t + 9.0 * c + 4.0 * c * c) * (a * a * a * a) / 24.0;
    let y2 = (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ep2) * (a * a * a * a * a * a) / 720.0;
    let y3 = (a * a) / 2.0 + y1 + y2;
    let y = 0.9996 * (m + n * latitude.tan() * y3);

    let northing = y;
    let easting = x + 500000.0;

    let meridian_convergence = meridian_convergence(northing, easting, WGS84);
    (northing, easting, meridian_convergence)
}

fn meridian_convergence(northing: f64, easting: f64, ellipsoid: Ellipsoid) -> f64 {
    let e2: f64 = 2.0 * ellipsoid.f - ellipsoid.f * ellipsoid.f;
    let e1 = (1.0 - (1.0 - e2).sqrt()) / (1.0 + (1.0 - e2).sqrt());
    let mu_const = ellipsoid.a * (1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0 - 5.0 * e2 * e2 * e2 / 256.0);

    let np = northing / 0.9996;
    let mu = np / mu_const;
    let foot_lat = footprint_latitude(e1, mu);

    let ep = (easting - 500000.0) / 0.9996;
    let n = ellipsoid.a / (1.0 - e2 * foot_lat.sin() * foot_lat.sin()).sqrt();
    let m = (ellipsoid.a * (1.0 - e2)) / (1.0 - e2 * foot_lat.sin() * foot_lat.sin()).powf(1.5);

    let conv1 = -(ep / n) * foot_lat.tan();
    let h30 = (ep / n).powi(3);
    let k28 = n / m;
    let k29 = k28 * k28;
    let j29 = foot_lat.tan() * foot_lat.tan();
    let conv2 = (foot_lat.tan() * h30 / 3.0) * (-2.0 * k29 + 3.0 * k28 + j29);
    conv1 + conv2
}

fn footprint_latitude(e1: f64, mu: f64) -> f64 {
    let term1 = 3.0 * e1 / 2.0 - 27.0 * e1 * e1 * e1 / 32.0;
    let term2 = 21.0 * e1 * e1 / 16.0 - 55.0 * e1 * e1 * e1 * e1 / 32.0;
    let term3 = 151.0 * e1 * e1 * e1 / 96.0;
    let term4 = 1097.0 * e1 * e1 * e1 * e1 / 512.0;

    mu + term1 * (2.0 * mu).sin() + term2 * (4.0 * mu).sin() + term3 * (6.0 * mu).sin() +
    term4 * (8.0 * mu).sin()
}

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

    #[test]
    fn reference() {
        let latitude = 60.9679875497;
        let longitude = -149.119325194;
        let (northing, easting, meridan_convgergence) = to_utm_wgs84(latitude, longitude, 6);
        assert!((385273.02 - easting).abs() < 1e-2);
        assert!((6761077.20 - northing).abs() < 1e-2);
        assert!((0.0323 - meridan_convgergence).abs() < 1e-4);
    }
}
<commit_msg>Fix some typos in function names<commit_after>//! Micro-library for converting from geodetic to UTM coordinates.

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

pub struct Ellipsoid {
    a: f64,
    f: f64,
}

const WGS84: Ellipsoid = Ellipsoid {
    a: 6378137.0,
    f: 1.0 / 298.257222101,
};

/// Converts a latitude and longitude in decimal degrees to UTM coordinates using the WGS84 ellipsoid.
///
/// # Examples
///
/// ```
/// use utm::to_utm_wgs84;
/// let (northing, easting, meridian_convergence) = to_utm_wgs84(40.62, -123.45, 10);
/// ```
pub fn to_utm_wgs84(latitude: f64, longitude: f64, zone: u8) -> (f64, f64, f64) {
    let latitude = latitude * PI / 180.0;
    let longitude = longitude * PI / 180.0;
    radians_to_utm_wgs84(latitude, longitude, zone)
}

/// Converts a latitude and longitude in radians to UTM coordinates using the WGS84 ellipsoid.
///
/// # Examples
///
/// ```
/// use std::f64::consts::PI;
/// use utm::radians_to_utm_wgs84;
/// let latitude = 40.62 * PI / 180.0;
/// let longitude = -123.45 * PI / 180.0;
/// let (northing, easting, meridian_convergence) = radians_to_utm_wgs84(latitude, longitude, 10);
/// ```
pub fn radians_to_utm_wgs84(latitude: f64, longitude: f64, zone: u8) -> (f64, f64, f64) {
    let ellipsoid = WGS84;
    let long_origin = zone as f64 * 6.0 - 183.0;
    let e2 = 2.0 * ellipsoid.f - ellipsoid.f * ellipsoid.f;
    let ep2 = e2 / (1.0 - e2);

    let n = ellipsoid.a / (1.0 - e2 * latitude.sin() * latitude.sin()).sqrt();
    let t = latitude.tan() * latitude.tan();
    let c = ep2 * latitude.cos() * latitude.cos();
    let a = latitude.cos() * (longitude - (long_origin * PI / 180.0));

    let term1 = 1.0 - e2 / 4.0 - (3.0 * e2 * e2) / 64.0 - (5.0 * e2 * e2 * e2) / 256.0;
    let term2 = (3.0 * e2) / 8.0 + (3.0 * e2 * e2) / 32.0 + (45.0 * e2 * e2 * e2) / 1024.0;
    let term3 = (15.0 * e2 * e2) / 256.0 + (45.0 * e2 * e2 * e2) / 1024.0;
    let term4 = (35.0 * e2 * e2 * e2) / 3072.0;

    let m = ellipsoid.a *
            (term1 * latitude - term2 * (2.0 * latitude).sin() + term3 * (4.0 * latitude).sin() -
             term4 * (6.0 * latitude).sin());

    let x1 = ((1.0 - t + c) * a * a * a) / 6.0;
    let x2 = ((5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ep2) * a * a * a * a * a) / 120.0;
    let x = 0.9996 * n * (a + x1 + x2);

    let y1 = (5.0 - t + 9.0 * c + 4.0 * c * c) * (a * a * a * a) / 24.0;
    let y2 = (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ep2) * (a * a * a * a * a * a) / 720.0;
    let y3 = (a * a) / 2.0 + y1 + y2;
    let y = 0.9996 * (m + n * latitude.tan() * y3);

    let northing = y;
    let easting = x + 500000.0;

    let meridian_convergence = meridian_convergence(northing, easting, WGS84);
    (northing, easting, meridian_convergence)
}

fn meridian_convergence(northing: f64, easting: f64, ellipsoid: Ellipsoid) -> f64 {
    let e2: f64 = 2.0 * ellipsoid.f - ellipsoid.f * ellipsoid.f;
    let e1 = (1.0 - (1.0 - e2).sqrt()) / (1.0 + (1.0 - e2).sqrt());
    let mu_const = ellipsoid.a * (1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0 - 5.0 * e2 * e2 * e2 / 256.0);

    let np = northing / 0.9996;
    let mu = np / mu_const;
    let foot_lat = footprint_latitude(e1, mu);

    let ep = (easting - 500000.0) / 0.9996;
    let n = ellipsoid.a / (1.0 - e2 * foot_lat.sin() * foot_lat.sin()).sqrt();
    let m = (ellipsoid.a * (1.0 - e2)) / (1.0 - e2 * foot_lat.sin() * foot_lat.sin()).powf(1.5);

    let conv1 = -(ep / n) * foot_lat.tan();
    let h30 = (ep / n).powi(3);
    let k28 = n / m;
    let k29 = k28 * k28;
    let j29 = foot_lat.tan() * foot_lat.tan();
    let conv2 = (foot_lat.tan() * h30 / 3.0) * (-2.0 * k29 + 3.0 * k28 + j29);
    conv1 + conv2
}

fn footprint_latitude(e1: f64, mu: f64) -> f64 {
    let term1 = 3.0 * e1 / 2.0 - 27.0 * e1 * e1 * e1 / 32.0;
    let term2 = 21.0 * e1 * e1 / 16.0 - 55.0 * e1 * e1 * e1 * e1 / 32.0;
    let term3 = 151.0 * e1 * e1 * e1 / 96.0;
    let term4 = 1097.0 * e1 * e1 * e1 * e1 / 512.0;

    mu + term1 * (2.0 * mu).sin() + term2 * (4.0 * mu).sin() + term3 * (6.0 * mu).sin() +
    term4 * (8.0 * mu).sin()
}

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

    #[test]
    fn reference() {
        let latitude = 60.9679875497;
        let longitude = -149.119325194;
        let (northing, easting, meridan_convgergence) = to_utm_wgs84(latitude, longitude, 6);
        assert!((385273.02 - easting).abs() < 1e-2);
        assert!((6761077.20 - northing).abs() < 1e-2);
        assert!((0.0323 - meridan_convgergence).abs() < 1e-4);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate clap;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P) -> Result<PathBuf> {
        let source = source.as_ref();
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" || lossy == "target" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .author(crate_authors!())
        .version(crate_version!())
        .usage("cargo template [FLAGS] <TEMPLATE> <NAME>")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    debug!("adding project & author info to the Cargo.toml");
    Ok(())
}<commit_msg>Add ability to update indices<commit_after>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate clap;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo, source)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P, url: &str) -> Result<PathBuf> {
        debug!("Updating index {}", url);
        println!("Updating index...");
        let source = source.as_ref();
        let repo = Repository::open(&source)?;
        let mut remote = repo.remote_anonymous(&url)?;
        let mut opts = git2::FetchOptions::new();
        opts.download_tags(git2::AutotagOption::All);
        let refspec = "refs/heads/*:refs/heads/*";
        remote.fetch(&[refspec], Some(&mut opts), None)?;
        let head = repo.head()?.target().unwrap();
        let obj = repo.find_object(head, None)?;
        repo.reset(&obj, git2::ResetType::Hard, None)?;
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" || lossy == "target" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .author(crate_authors!())
        .version(crate_version!())
        .usage("cargo template [FLAGS] <TEMPLATE> <NAME>")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    debug!("adding project & author info to the Cargo.toml");
    Ok(())
}<|endoftext|>


<commit_before>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```
#[cfg(windows)]
extern crate winapi;

use std::{
    ffi::OsStr,
    process::{Command, Stdio},
    io,
    process::ExitStatus,
    thread
};

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    let path_ref = path.as_ref();
    let mut last_err: io::Error = io::Error::from_raw_os_error(0);
    for program in &["xdg-open", "gnome-open", "kde-open", "wslview"] {
        match Command::new(program)
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path_ref)
            .spawn()
        {
            Ok(mut child) => return child.wait(),
            Err(err) => {
                last_err = err;
                continue;
            }
        }
    }
    Err(last_err)
}

#[cfg(target_os = "windows")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    const SW_SHOW: c_int = 5;

    let path = windows::convert_path(path.as_ref())?;
    let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
    let result = unsafe {
        ShellExecuteW(
            ptr::null_mut(),
            operation.as_ptr(),
            path.as_ptr(),
            ptr::null(),
            ptr::null(),
            SW_SHOW,
        )
    };
    if result as c_int > 32 {
        Ok(ExitStatus::from_raw(0))
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(target_os = "macos")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    Command::new("open")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .arg(path.as_ref())
        .spawn()?
        .wait()
}

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::ffi::OsStrExt;

    pub fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
}
<commit_msg>add with function<commit_after>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```
#[cfg(windows)]
extern crate winapi;

#[cfg(not(windows))]
use std::process::Stdio;

use std::{
    ffi::OsStr,
    io,
    process::ExitStatus,
    thread
};

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    let path_ref = path.as_ref();
    let mut last_err: io::Error = io::Error::from_raw_os_error(0);
    for program in &["xdg-open", "gnome-open", "kde-open", "wslview"] {
        match Command::new(program)
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path_ref)
            .spawn()
        {
            Ok(mut child) => return child.wait(),
            Err(err) => {
                last_err = err;
                continue;
            }
        }
    }
    Err(last_err)
}

#[cfg(target_os = "windows")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    const SW_SHOW: c_int = 5;

    let path = windows::convert_path(path.as_ref())?;
    let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
    let result = unsafe {
        ShellExecuteW(
            ptr::null_mut(),
            operation.as_ptr(),
            path.as_ptr(),
            ptr::null(),
            ptr::null(),
            SW_SHOW,
        )
    };
    if result as c_int > 32 {
        Ok(ExitStatus::from_raw(0))
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(target_os = "macos")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    Command::new("open")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .arg(path.as_ref())
        .spawn()?
        .wait()
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn with<T:AsRef<OsStr>+Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    Command::new(app.into())
        .arg(path.as_ref())
        .spawn()?
        .wait()
}

#[cfg(target_os = "windows")]
pub fn with<T:AsRef<OsStr>+Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    const SW_SHOW: c_int = 5;

    let path = windows::convert_path(path.as_ref())?;
    let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
    let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into())).encode_wide().collect();
    let result = unsafe {
        ShellExecuteW(
            ptr::null_mut(),
            operation.as_ptr(),
            app_name.as_ptr(),
            path.as_ptr(),
            ptr::null(),
            SW_SHOW,
        )
    };
    if result as c_int > 32 {
        Ok(ExitStatus::from_raw(0))
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(target_os = "macos")]
pub fn with<T:AsRef<OsStr>+Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    Command::new("open")
        .arg(path.as_ref())
        .arg("-a")
        .arg(app.into())
        .spawn()?
        .wait()
}

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::ffi::OsStrExt;

    pub fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
}
<|endoftext|>


<commit_before>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.11")]
#![deny(missing_docs)]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    // private Deserializer::next
    should_implement_trait,
    // things are often more readable this way
    cast_lossless,
    module_name_repetitions,
    single_match_else,
    use_self,
    // code is acceptable
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
    // not practical
    indexing_slicing,
    missing_docs_in_private_items,
    // not stable
    checked_conversions,
    empty_enum,
    // meh, some things won't fail
    result_unwrap_used,
    // noisy
    must_use_candidate,
))]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::mapping::Mapping;
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;
<commit_msg>Ignore missing_errors_doc pedantic lint<commit_after>//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.11")]
#![deny(missing_docs)]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    // private Deserializer::next
    should_implement_trait,
    // things are often more readable this way
    cast_lossless,
    module_name_repetitions,
    single_match_else,
    use_self,
    // code is acceptable
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
    // not practical
    indexing_slicing,
    missing_docs_in_private_items,
    // not stable
    checked_conversions,
    empty_enum,
    // meh, some things won't fail
    result_unwrap_used,
    // noisy
    missing_errors_doc,
    must_use_candidate,
))]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::mapping::Mapping;
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;
<|endoftext|>


<commit_before>extern crate regex;

extern crate rusoto_core;
extern crate rusoto_sts;
extern crate rusoto_dynamodb;

pub mod SessionHandler {
    use std::fs::{File, OpenOptions};
    use std::io::{BufReader, Error};
    use std::io;
    use std::io::prelude::*;
    use std::io::{stdin, stdout};
    use std::env;
    use rusoto_core::{DefaultCredentialsProvider, ProfileProvider,
        ProvideAwsCredentials, Region, default_tls_client};
    use rusoto_sts::{Sts, StsClient, GetSessionTokenRequest, GetSessionTokenResponse, GetSessionTokenError, Credentials};
    use rusoto_dynamodb::{DynamoDb, DynamoDbClient, ListTablesInput};
    use regex::Regex;
    use std::collections::HashMap;

    pub struct SessionHandler {
        AWSConfig: AWSConfig,
    }

    struct AWSConfig {
        profiles: HashMap<String, AWSProfile>,
    }

    #[derive(Debug)]
    struct AWSProfile {
        source_profile: Option<String>,
        region: Option<String>,
        output: Option<String>,
        role_arn: Option<String>,
        mfa_serial: Option<String>,
        ot_session_name: Option<String>,
        ot_expiration: Option<String>,
        ot_source_profile: Option<String>,
        ot_role_arn: Option<String>,
    }

    impl AWSConfig {
        fn get_profile(&self, name: &str) -> &AWSProfile {
            &self.profiles[name]
        }
    }

    impl SessionHandler {
        pub fn load_config(&mut self) {
            let aws_config_file = read_aws_config_file();
            let profiles = split_config_file(aws_config_file);

            // Create an instance of the AWSConfig struct
            let mut aws_config = AWSConfig {
                profiles: HashMap::new()
            };

            // Iterate over profile chunks
            for profile in profiles {
                // Create a vector of string that holds each line
                let split = profile.split("\n");
                let lines: Vec<String> = split.map(|s| s.to_string()).collect();

                // Get the profile name from the first line
                let profile_line = lines[0].to_owned();

                // Lets ignore the default for now
                if profile_line == "[default]" {
                    continue;
                }

                let split2 = profile_line.split(" ");
                let mut words: Vec<String> = split2.map(|s| s.to_string()).collect();
                let mut profile_name = String::new();
                if words.len() > 1 {
                    words[1].pop();
                    profile_name = words[1].trim_right().to_owned();
                }

                let mut aws_profile = AWSProfile{
                    source_profile: None,
                    region: None,
                    output: None,
                    role_arn: None,
                    mfa_serial: None,
                    ot_expiration: None,
                    ot_session_name: None,
                    ot_source_profile: None,
                    ot_role_arn: None,
                };

                for i in 1..lines.len() {
                    let split = lines[i].split(" = ");
                    let config: Vec<String> = split.map(|s| s.to_string()).collect();
                    let key = &config[0];
                    let value = config[1].to_owned();
                    match key.as_ref() {
                        "mfa_serial" => aws_profile.mfa_serial = Some(value),
                        "output" => aws_profile.output = Some(value),
                        "region" => aws_profile.region = Some(value),
                        "role_arn" => aws_profile.role_arn = Some(value),
                        "source_profile" => aws_profile.source_profile = Some(value),
                        "ot_session_name" => aws_profile.ot_session_name = Some(value),
                        "ot_expiration" => aws_profile.ot_expiration = Some(value),
                        "ot_source_profile" => aws_profile.ot_source_profile = Some(value),
                        "ot_role_arn" => aws_profile.ot_role_arn = Some(value),
                        _ => (),
                    }
                }

                if profile_name != "" {
                    aws_config.profiles.insert(profile_name.clone(), aws_profile);
                }
            }

            self.AWSConfig = aws_config;
        }

        pub fn create(&self, profile_name: &str) {
            println!("Creating session for profile \"{}\"...", profile_name);
            //let aws_profile = &self.AWSConfig.profiles[profile_name];
            let aws_profile = &self.AWSConfig.get_profile(profile_name);

            let mut provider = ProfileProvider::new().unwrap();
            provider.set_profile(profile_name);
            // let region = &aws_profile.region;
            // match region {
            //     &Some(ref region) => region,
            //     &None => panic!("You must specify a region for profile {}", profile_name)
            // };
            // println!("Region: {:?}", region.as_ref().unwrap());
            let client = StsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);

            let mfa_serial = &aws_profile.mfa_serial;
            if mfa_serial.is_some() {
                print!("Enter AWS MFA code for profile [{}]: ", profile_name);
                stdout().flush();
                let mut token_code = String::new();
                stdin().read_line(&mut token_code)
                    .ok()
                    .expect("Couldn't read line");
                token_code.pop(); // Remove newline

                let request = GetSessionTokenRequest {
                    duration_seconds: None,
                    serial_number: Some(mfa_serial.as_ref().unwrap().to_owned()),
                    token_code: Some(token_code),
                };
                let response = client.get_session_token(&request);
                match response {
                    Ok(response) => {
                        let credentials = response.credentials.unwrap();
                        match save_credentials(profile_name, credentials) {
                            Ok(_) => println!("Saved to credentials file."),
                            Err(err) => println!("Error saving credentials to file: {:?}", err)
                        };
                    },
                    Err(err) => panic!("Failed to get session token for profile {}: {:?}", profile_name, err),
                };
            }
        }

        pub fn show(&self, profile_name: &str) {
            println!("Showing config for profile {}...", profile_name);
            println!("{:?}", self.AWSConfig.profiles[profile_name]);
        }
    }

    pub fn create(profile_name: &str) {
        println!("Creating session for profile \"{}\"...", profile_name);

    }

    pub fn new() -> SessionHandler {
            SessionHandler {
                AWSConfig: AWSConfig {
                    profiles: HashMap::new()
                }
            }
    }

    pub fn refresh() {
        println!("Refreshing sessions...");
    }

    pub fn clean() {
        println!("Cleaning sessions...");
    }

    fn read_aws_config_file() -> String {
        let path = match env::home_dir() {
            Some(path) => path,
            None => panic!("Could not retrieve user's home directory."),
        };
        let config_file_path = format!("{}/.aws/config", path.display());

        let f = File::open(config_file_path).expect("Could not find AWS config file.");
        let mut buf_reader = BufReader::new(f);
        let mut contents = String::new();
        buf_reader.read_to_string(&mut contents).expect("Found config file but could not read it.");

        contents
    }

    fn split_config_file(aws_config: String) -> Vec<String> {
        let split = aws_config.split("\n\n");
        let mut profiles: Vec<String> = split.map(|s| s.to_string()).collect();;

        profiles.pop(); // Remove last element as it is always empty
        profiles
    }

    fn save_credentials(profile_name: &str, credentials: Credentials) -> Result<(), io::Error> {
        let mut aws_credentials_path = env::home_dir().unwrap().display().to_string();
        aws_credentials_path.push_str("/.aws/credentials");
        let mut file = OpenOptions::new()
                       .write(true)
                       .append(true)
                       .open(aws_credentials_path)
                       .unwrap();

        let mut creds = String::new();
        creds.push_str(&format!("[{}-session]\n", profile_name));
        creds.push_str(&format!("access_key_id = {}\n", credentials.access_key_id));
        creds.push_str(&format!("expiration = {}\n", credentials.expiration));
        creds.push_str(&format!("secret_access_key = {}\n", credentials.secret_access_key));
        creds.push_str(&format!("session_token = {}\n", credentials.session_token));
        try!(file.write_all(creds.as_bytes()));
        Ok(())
    }
}
<commit_msg>Add save profile function<commit_after>extern crate regex;

extern crate rusoto_core;
extern crate rusoto_sts;
extern crate rusoto_dynamodb;

pub mod SessionHandler {
    use std::fs::{File, OpenOptions};
    use std::io::BufReader;
    use std::io;
    use std::io::prelude::*;
    use std::io::{stdin, stdout};
    use std::env;
    use rusoto_core::{ProfileProvider, Region, default_tls_client};
    use rusoto_sts::{Sts, StsClient, GetSessionTokenRequest, GetSessionTokenResponse, GetSessionTokenError, Credentials};
    use std::collections::HashMap;

    pub struct SessionHandler {
        AWSConfig: AWSConfig,
    }

    struct AWSConfig {
        profiles: HashMap<String, AWSProfile>,
    }

    #[derive(Debug)]
    struct AWSProfile {
        source_profile: Option<String>,
        region: Option<String>,
        output: Option<String>,
        role_arn: Option<String>,
        mfa_serial: Option<String>,
        ot_session_name: Option<String>,
        ot_expiration: Option<String>,
        ot_source_profile: Option<String>,
        ot_role_arn: Option<String>,
    }

    impl AWSConfig {
        fn get_profile(&self, name: &str) -> &AWSProfile {
            &self.profiles[name]
        }
    }

    impl SessionHandler {
        pub fn load_config(&mut self) {
            let aws_config_file = read_aws_config_file();
            let profiles = split_config_file(aws_config_file);

            // Create an instance of the AWSConfig struct
            let mut aws_config = AWSConfig {
                profiles: HashMap::new()
            };

            // Iterate over profile chunks
            for profile in profiles {
                // Create a vector of string that holds each line
                let split = profile.split("\n");
                let lines: Vec<String> = split.map(|s| s.to_string()).collect();

                // Get the profile name from the first line
                let profile_line = lines[0].to_owned();

                // Lets ignore the default for now
                if profile_line == "[default]" {
                    continue;
                }

                let split2 = profile_line.split(" ");
                let mut words: Vec<String> = split2.map(|s| s.to_string()).collect();
                let mut profile_name = String::new();
                if words.len() > 1 {
                    words[1].pop();
                    profile_name = words[1].trim_right().to_owned();
                }

                let mut aws_profile = AWSProfile{
                    source_profile: None,
                    region: None,
                    output: None,
                    role_arn: None,
                    mfa_serial: None,
                    ot_expiration: None,
                    ot_session_name: None,
                    ot_source_profile: None,
                    ot_role_arn: None,
                };

                for i in 1..lines.len() {
                    let split = lines[i].split(" = ");
                    let config: Vec<String> = split.map(|s| s.to_string()).collect();
                    let key = &config[0];
                    let value = config[1].to_owned();
                    match key.as_ref() {
                        "mfa_serial" => aws_profile.mfa_serial = Some(value),
                        "output" => aws_profile.output = Some(value),
                        "region" => aws_profile.region = Some(value),
                        "role_arn" => aws_profile.role_arn = Some(value),
                        "source_profile" => aws_profile.source_profile = Some(value),
                        "ot_session_name" => aws_profile.ot_session_name = Some(value),
                        "ot_expiration" => aws_profile.ot_expiration = Some(value),
                        "ot_source_profile" => aws_profile.ot_source_profile = Some(value),
                        "ot_role_arn" => aws_profile.ot_role_arn = Some(value),
                        _ => (),
                    }
                }

                if profile_name != "" {
                    aws_config.profiles.insert(profile_name.clone(), aws_profile);
                }
            }

            self.AWSConfig = aws_config;
        }

        pub fn create(&self, profile_name: &str) {
            println!("Creating session for profile \"{}\"...", profile_name);
            let aws_profile = &self.AWSConfig.get_profile(profile_name);

            let mut provider = ProfileProvider::new().unwrap();
            provider.set_profile(profile_name);
            // let region = &aws_profile.region;
            // match region {
            //     &Some(ref region) => region,
            //     &None => panic!("You must specify a region for profile {}", profile_name)
            // };
            // println!("Region: {:?}", region.as_ref().unwrap());
            let client = StsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);

            let mfa_serial = &aws_profile.mfa_serial;
            if mfa_serial.is_some() {
                print!("Enter AWS MFA code for profile [{}]: ", profile_name);
                stdout().flush();
                let mut token_code = String::new();
                stdin().read_line(&mut token_code)
                    .ok()
                    .expect("Couldn't read line");
                token_code.pop(); // Remove newline

                let request = GetSessionTokenRequest {
                    duration_seconds: None,
                    serial_number: Some(mfa_serial.as_ref().unwrap().to_owned()),
                    token_code: Some(token_code),
                };
                let response = client.get_session_token(&request);
                match response {
                    Ok(response) => {
                        match save_profile(profile_name, &aws_profile) {
                            Ok(_) => println!("Saved profile to config file."),
                            Err(err) => println!("Error saving profile config to file: {:?}", err)
                        };
                        let credentials = response.credentials.unwrap();
                        match save_credentials(profile_name, credentials) {
                            Ok(_) => println!("Saved to credentials file."),
                            Err(err) => println!("Error saving credentials to file: {:?}", err)
                        };
                    },
                    Err(err) => panic!("Failed to get session token for profile {}: {:?}", profile_name, err),
                };
            }
        }

        pub fn show(&self, profile_name: &str) {
            println!("Showing config for profile {}...", profile_name);
            println!("{:?}", self.AWSConfig.profiles[profile_name]);
        }
    }

    pub fn create(profile_name: &str) {
        println!("Creating session for profile \"{}\"...", profile_name);

    }

    pub fn new() -> SessionHandler {
            SessionHandler {
                AWSConfig: AWSConfig {
                    profiles: HashMap::new()
                }
            }
    }

    pub fn refresh() {
        println!("Refreshing sessions...");
    }

    pub fn clean() {
        println!("Cleaning sessions...");
    }

    fn read_aws_config_file() -> String {
        let path = match env::home_dir() {
            Some(path) => path,
            None => panic!("Could not retrieve user's home directory."),
        };
        let config_file_path = format!("{}/.aws/config", path.display());

        let f = File::open(config_file_path).expect("Could not find AWS config file.");
        let mut buf_reader = BufReader::new(f);
        let mut contents = String::new();
        buf_reader.read_to_string(&mut contents).expect("Found config file but could not read it.");

        contents
    }

    fn split_config_file(aws_config: String) -> Vec<String> {
        let split = aws_config.split("\n\n");
        let mut profiles: Vec<String> = split.map(|s| s.to_string()).collect();;

        profiles.pop(); // Remove last element as it is always empty
        profiles
    }

    fn save_credentials(profile_name: &str, credentials: Credentials) -> Result<(), io::Error> {
        let mut aws_credentials_path = env::home_dir().unwrap().display().to_string();
        aws_credentials_path.push_str("/.aws/credentials");
        let mut file = OpenOptions::new()
                       .write(true)
                       .append(true)
                       .open(aws_credentials_path)
                       .unwrap();

        let mut creds = String::new();
        creds.push_str(&format!("[{}-session]\n", profile_name));
        creds.push_str(&format!("aws_access_key_id = {}\n", credentials.access_key_id));
        creds.push_str(&format!("expiration = {}\n", credentials.expiration));
        creds.push_str(&format!("aws_secret_access_key = {}\n", credentials.secret_access_key));
        creds.push_str(&format!("aws_session_token = {}\n", credentials.session_token));
        try!(file.write_all(creds.as_bytes()));
        Ok(())
    }

    fn save_profile(profile_name: &str, aws_profile: &AWSProfile) -> Result<(), io::Error> {
        let mut aws_config_path = env::home_dir().unwrap().display().to_string();
        aws_config_path.push_str("/.aws/config");
        let mut file = OpenOptions::new()
                       .write(true)
                       .append(true)
                       .open(aws_config_path)
                       .unwrap();

        let region = &aws_profile.region;
        match region {
            &Some(ref region) => {
                let mut prof = String::new();
                prof.push_str(&format!("[profile {}-session]\n", profile_name));
                prof.push_str(&format!("region = {:?}\n", region));
                try!(file.write_all(prof.as_bytes()));
                Ok(())
            },
            &None => {
                let region = "us-east-1";
                let mut prof = String::new();
                prof.push_str(&format!("[{}-session]\n", profile_name));
                prof.push_str(&format!("region = {:?}\n", region));
                try!(file.write_all(prof.as_bytes()));
                Ok(())
            },
        }
    }
}
<|endoftext|>


<commit_before>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
//!
//! Provides a lint that warns/errors when a function calls a method that is marked with a
//! particular kind of unsafety.
//!
//! Four attributes are used to allow functions to be marked.
//! - `#[not_safe(tags)]` - Marks a function as not being safe for the given tags
//! - `#[is_safe(tags)]` - Marks the function as being safe for the given tags (despite what it does internally)
//! - `#[tagged_safe(tag="file")]` Loads a list of tagged functions for an extern crate from a file.
//! - `#[req_safe(tags)]` - Enables linting this function for use the given tags
//!
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
#![feature(macro_vis_matcher)]  // needed for some random macro?

#[macro_use]
extern crate log;

#[macro_use]
extern crate lazy_static;

extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_plugin;

mod prescan;
mod check;
mod database;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut ::rustc_plugin::Registry) {
    use syntax::feature_gate::AttributeType;
    use syntax::ext::base::SyntaxExtension;
    use syntax::symbol::Symbol;

    reg.register_syntax_extension(Symbol::intern("tagged_safe"), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerTaggedSafe)) );
    //reg.register_syntax_extension(intern("is_safe" ), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerIsSafe) ) );
    //reg.register_syntax_extension(intern("not_safe"), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerNotSafe)) );
    //reg.register_syntax_extension(intern("req_safe"), SyntaxExtension::MultiModifier(Box::new(prescan::HandlerReqSafe)) );

    reg.register_late_lint_pass( Box::new(check::Pass::default()) );

    reg.register_attribute(String::from("is_safe" ), AttributeType::Whitelisted);
    reg.register_attribute(String::from("not_safe"), AttributeType::Whitelisted);
    reg.register_attribute(String::from("req_safe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<commit_msg>Add a feature flag needed by internal macros<commit_after>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
//!
//! Provides a lint that warns/errors when a function calls a method that is marked with a
//! particular kind of unsafety.
//!
//! Four attributes are used to allow functions to be marked.
//! - `#[not_safe(tags)]` - Marks a function as not being safe for the given tags
//! - `#[is_safe(tags)]` - Marks the function as being safe for the given tags (despite what it does internally)
//! - `#[tagged_safe(tag="file")]` Loads a list of tagged functions for an extern crate from a file.
//! - `#[req_safe(tags)]` - Enables linting this function for use the given tags
//!
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
#![feature(macro_vis_matcher)]  // needed for some random macro?
#![feature(macro_at_most_once_rep)] // also needed for a macro (lint_array)

#[macro_use]
extern crate log;

#[macro_use]
extern crate lazy_static;

extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_plugin;

mod prescan;
mod check;
mod database;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut ::rustc_plugin::Registry) {
    use syntax::feature_gate::AttributeType;
    use syntax::ext::base::SyntaxExtension;
    use syntax::symbol::Symbol;

    reg.register_syntax_extension(Symbol::intern("tagged_safe"), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerTaggedSafe)) );
    //reg.register_syntax_extension(intern("is_safe" ), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerIsSafe) ) );
    //reg.register_syntax_extension(intern("not_safe"), SyntaxExtension::MultiDecorator(Box::new(prescan::HandlerNotSafe)) );
    //reg.register_syntax_extension(intern("req_safe"), SyntaxExtension::MultiModifier(Box::new(prescan::HandlerReqSafe)) );

    reg.register_late_lint_pass( Box::new(check::Pass::default()) );

    reg.register_attribute(String::from("is_safe" ), AttributeType::Whitelisted);
    reg.register_attribute(String::from("not_safe"), AttributeType::Whitelisted);
    reg.register_attribute(String::from("req_safe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<|endoftext|>