<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::EventBinding;
use dom::bindings::codegen::EventBinding::EventConstants;
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::Fallible;
use dom::eventtarget::EventTarget;
use dom::window::Window;
use servo_util::str::DOMString;

use geom::point::Point2D;

pub enum Event_ {
    ResizeEvent(uint, uint),
    ReflowEvent,
    ClickEvent(uint, Point2D<f32>),
    MouseDownEvent(uint, Point2D<f32>),
    MouseUpEvent(uint, Point2D<f32>),
    MouseMoveEvent(Point2D<f32>)
}

#[deriving(Encodable)]
pub enum EventPhase {
    PhaseNone      = EventConstants::NONE,
    PhaseCapturing = EventConstants::CAPTURING_PHASE,
    PhaseAtTarget  = EventConstants::AT_TARGET,
    PhaseBubbling  = EventConstants::BUBBLING_PHASE,
}

#[deriving(Eq, Encodable)]
pub enum EventTypeId {
    HTMLEventTypeId,
    UIEventTypeId,
    MouseEventTypeId,
    KeyEventTypeId
}

#[deriving(Encodable)]
pub struct Event {
    pub type_id: EventTypeId,
    pub reflector_: Reflector,
    pub current_target: Option<JS<EventTarget>>,
    pub target: Option<JS<EventTarget>>,
    pub type_: DOMString,
    pub phase: EventPhase,
    pub canceled: bool,
    pub stop_propagation: bool,
    pub stop_immediate: bool,
    pub cancelable: bool,
    pub bubbles: bool,
    pub trusted: bool,
    pub dispatching: bool,
    pub initialized: bool,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            type_id: type_id,
            reflector_: Reflector::new(),
            current_target: None,
            target: None,
            phase: PhaseNone,
            type_: ~"",
            canceled: false,
            cancelable: true,
            bubbles: true,
            trusted: false,
            dispatching: false,
            stop_propagation: false,
            stop_immediate: false,
            initialized: false,
        }
    }

    pub fn new(window: &JS<Window>) -> JS<Event> {
        reflect_dom_object(~Event::new_inherited(HTMLEventTypeId),
                           window,
                           EventBinding::Wrap)
    }

    pub fn EventPhase(&self) -> u16 {
        self.phase as u16
    }

    pub fn Type(&self) -> DOMString {
        self.type_.clone()
    }

    pub fn GetTarget(&self) -> Option<JS<EventTarget>> {
        self.target.clone()
    }

    pub fn GetCurrentTarget(&self) -> Option<JS<EventTarget>> {
        self.current_target.clone()
    }

    pub fn DefaultPrevented(&self) -> bool {
        self.canceled
    }

    pub fn PreventDefault(&mut self) {
        if self.cancelable {
            self.canceled = true
        }
    }

    pub fn StopPropagation(&mut self) {
        self.stop_propagation = true;
    }

    pub fn StopImmediatePropagation(&mut self) {
        self.stop_immediate = true;
        self.stop_propagation = true;
    }

    pub fn Bubbles(&self) -> bool {
        self.bubbles
    }

    pub fn Cancelable(&self) -> bool {
        self.cancelable
    }

    pub fn TimeStamp(&self) -> u64 {
        0
    }

    pub fn InitEvent(&mut self,
                     type_: DOMString,
                     bubbles: bool,
                     cancelable: bool) {
        self.initialized = true;
        if self.dispatching {
            return;
        }
        self.stop_propagation = false;
        self.stop_immediate = false;
        self.canceled = false;
        self.trusted = false;
        self.target = None;
        self.type_ = type_;
        self.bubbles = bubbles;
        self.cancelable = cancelable;
    }

    pub fn IsTrusted(&self) -> bool {
        self.trusted
    }

    pub fn Constructor(global: &JS<Window>,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<JS<Event>> {
        let mut ev = Event::new(global);
        ev.get_mut().InitEvent(type_, init.bubbles, init.cancelable);
        Ok(ev)
    }
}

impl Reflectable for Event {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}
<commit_msg>auto merge of #2233 : campadrenalin/servo/initialize-event-bubbling-to-false, r=Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::EventBinding;
use dom::bindings::codegen::EventBinding::EventConstants;
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::Fallible;
use dom::eventtarget::EventTarget;
use dom::window::Window;
use servo_util::str::DOMString;

use geom::point::Point2D;

pub enum Event_ {
    ResizeEvent(uint, uint),
    ReflowEvent,
    ClickEvent(uint, Point2D<f32>),
    MouseDownEvent(uint, Point2D<f32>),
    MouseUpEvent(uint, Point2D<f32>),
    MouseMoveEvent(Point2D<f32>)
}

#[deriving(Encodable)]
pub enum EventPhase {
    PhaseNone      = EventConstants::NONE,
    PhaseCapturing = EventConstants::CAPTURING_PHASE,
    PhaseAtTarget  = EventConstants::AT_TARGET,
    PhaseBubbling  = EventConstants::BUBBLING_PHASE,
}

#[deriving(Eq, Encodable)]
pub enum EventTypeId {
    HTMLEventTypeId,
    UIEventTypeId,
    MouseEventTypeId,
    KeyEventTypeId
}

#[deriving(Encodable)]
pub struct Event {
    pub type_id: EventTypeId,
    pub reflector_: Reflector,
    pub current_target: Option<JS<EventTarget>>,
    pub target: Option<JS<EventTarget>>,
    pub type_: DOMString,
    pub phase: EventPhase,
    pub canceled: bool,
    pub stop_propagation: bool,
    pub stop_immediate: bool,
    pub cancelable: bool,
    pub bubbles: bool,
    pub trusted: bool,
    pub dispatching: bool,
    pub initialized: bool,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            type_id: type_id,
            reflector_: Reflector::new(),
            current_target: None,
            target: None,
            phase: PhaseNone,
            type_: ~"",
            canceled: false,
            cancelable: true,
            bubbles: false,
            trusted: false,
            dispatching: false,
            stop_propagation: false,
            stop_immediate: false,
            initialized: false,
        }
    }

    pub fn new(window: &JS<Window>) -> JS<Event> {
        reflect_dom_object(~Event::new_inherited(HTMLEventTypeId),
                           window,
                           EventBinding::Wrap)
    }

    pub fn EventPhase(&self) -> u16 {
        self.phase as u16
    }

    pub fn Type(&self) -> DOMString {
        self.type_.clone()
    }

    pub fn GetTarget(&self) -> Option<JS<EventTarget>> {
        self.target.clone()
    }

    pub fn GetCurrentTarget(&self) -> Option<JS<EventTarget>> {
        self.current_target.clone()
    }

    pub fn DefaultPrevented(&self) -> bool {
        self.canceled
    }

    pub fn PreventDefault(&mut self) {
        if self.cancelable {
            self.canceled = true
        }
    }

    pub fn StopPropagation(&mut self) {
        self.stop_propagation = true;
    }

    pub fn StopImmediatePropagation(&mut self) {
        self.stop_immediate = true;
        self.stop_propagation = true;
    }

    pub fn Bubbles(&self) -> bool {
        self.bubbles
    }

    pub fn Cancelable(&self) -> bool {
        self.cancelable
    }

    pub fn TimeStamp(&self) -> u64 {
        0
    }

    pub fn InitEvent(&mut self,
                     type_: DOMString,
                     bubbles: bool,
                     cancelable: bool) {
        self.initialized = true;
        if self.dispatching {
            return;
        }
        self.stop_propagation = false;
        self.stop_immediate = false;
        self.canceled = false;
        self.trusted = false;
        self.target = None;
        self.type_ = type_;
        self.bubbles = bubbles;
        self.cancelable = cancelable;
    }

    pub fn IsTrusted(&self) -> bool {
        self.trusted
    }

    pub fn Constructor(global: &JS<Window>,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<JS<Event>> {
        let mut ev = Event::new(global);
        ev.get_mut().InitEvent(type_, init.bubbles, init.cancelable);
        Ok(ev)
    }
}

impl Reflectable for Event {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}
<|endoftext|>


<commit_before>//! A scalable reader-writer lock.
//!
//! This implementation makes read operations faster and more scalable due to less contention,
//! while making write operations slower. It also incurs much higher memory overhead than
//! traditional reader-writer locks.

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::Mutex;
use std::thread::{self, ThreadId};

use crossbeam_utils::CachePadded;
use num_cpus;
use parking_lot;

/// A scalable read-writer lock.
///
/// This type of lock allows a number of readers or at most one writer at any point in time. The
/// write portion of this lock typically allows modification of the underlying data (exclusive
/// access) and the read portion of this lock typically allows for read-only access (shared
/// access).
///
/// This reader-writer lock differs from typical implementations in that it internally creates a
/// list of reader-writer locks called 'shards'. Shards are aligned and padded to the cache line
/// size.
///
/// Read operations lock only one shard specific to the current thread, while write operations lock
/// every shard in succession. This strategy makes concurrent read operations faster due to less
/// contention, but write operations are slower due to increased amount of locking.
pub struct RwLock<T> {
    /// A list of locks protecting the internal data.
    shards: Vec<CachePadded<parking_lot::RwLock<()>>>,

    /// The internal data.
    value: UnsafeCell<T>,
}

unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Send + Sync> Sync for RwLock<T> {}

impl<T> RwLock<T> {
    /// Creates a new `RwLock` initialized with `value`.
    pub fn new(value: T) -> RwLock<T> {
        // The number of shards is a power of two so that the modulo operation in `read` becomes a
        // simple bitwise "and".
        let num_shards = num_cpus::get().next_power_of_two();

        RwLock {
            shards: (0..num_shards)
                .map(|_| CachePadded::new(parking_lot::RwLock::new(())))
                .collect(),
            value: UnsafeCell::new(value),
        }
    }

    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be
    /// acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which hold the lock.
    /// There may be other readers currently inside the lock when this method returns. This method
    /// does not provide any guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access once it is dropped.
    pub fn read(&self) -> RwLockReadGuard<T> {
        // Take the current thread index and map it to a shard index. Thread indices will tend to
        // distribute shards among threads equally, thus reducing contention due to read-locking.
        let shard_index = thread_index() & (self.shards.len() - 1);

        RwLockReadGuard {
            parent: self,
            _guard: self.shards[shard_index].read(),
            _marker: PhantomData,
        }
    }

    /// Locks this rwlock with exclusive write access, blocking the current thread until it can be
    /// acquired.
    ///
    /// This function will not return while other writers or other readers currently have access to
    /// the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock when dropped.
    pub fn write(&self) -> RwLockWriteGuard<T> {
        // Write-lock each shard in succession.
        for shard in &self.shards {
            // The write guard is forgotten, but the lock will be manually unlocked in `drop`.
            mem::forget(shard.write());
        }

        RwLockWriteGuard {
            parent: self,
            _marker: PhantomData,
        }
    }
}

/// A guard used to release the shared read access of a `RwLock` when dropped.
pub struct RwLockReadGuard<'a, T: 'a> {
    parent: &'a RwLock<T>,
    _guard: parking_lot::RwLockReadGuard<'a, ()>,
    _marker: PhantomData<parking_lot::RwLockReadGuard<'a, T>>,
}

unsafe impl<'a, T: Sync> Sync for RwLockReadGuard<'a, T> {}

impl<'a, T> Deref for RwLockReadGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.parent.value.get() }
    }
}

/// A guard used to release the exclusive write access of a `RwLock` when dropped.
pub struct RwLockWriteGuard<'a, T: 'a> {
    parent: &'a RwLock<T>,
    _marker: PhantomData<parking_lot::RwLockWriteGuard<'a, T>>,
}

unsafe impl<'a, T: Sync> Sync for RwLockWriteGuard<'a, T> {}

impl<'a, T> Drop for RwLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        // Unlock the shards in reverse order of locking.
        for shard in self.parent.shards.iter().rev() {
            unsafe {
                shard.force_unlock_write();
            }
        }
    }
}

impl<'a, T> Deref for RwLockWriteGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

/// Returns a `usize` that identifies the current thread.
///
/// Each thread is associated with an 'index'. While there are no particular guarantees, indices
/// usually tend to be consecutive numbers between 0 and the number of running threads.
#[inline]
pub fn thread_index() -> usize {
    REGISTRATION.with(|reg| reg.index)
}

/// The global registry keeping track of registered threads and indices.
struct ThreadIndices {
    /// Mapping from `ThreadId` to thread index.
    mapping: HashMap<ThreadId, usize>,

    /// A list of free indices.
    free_list: Vec<usize>,

    /// The next index to allocate if the free list is empty.
    next_index: usize,
}

lazy_static! {
    static ref THREAD_INDICES: Mutex<ThreadIndices> = Mutex::new(ThreadIndices {
        mapping: HashMap::new(),
        free_list: Vec::new(),
        next_index: 0,
    });
}

/// A registration of a thread with an index.
///
/// When dropped, unregisters the thread and frees the reserved index.
struct Registration {
    index: usize,
    thread_id: ThreadId,
}

impl Drop for Registration {
    fn drop(&mut self) {
        let mut indices = THREAD_INDICES.lock().unwrap();
        indices.mapping.remove(&self.thread_id);
        indices.free_list.push(self.index);
    }
}

thread_local! {
    static REGISTRATION: Registration = {
        let thread_id = thread::current().id();
        let mut indices = THREAD_INDICES.lock().unwrap();

        let index = match indices.free_list.pop() {
            Some(i) => i,
            None => {
                let i = indices.next_index;
                indices.next_index += 1;
                i
            }
        };
        indices.mapping.insert(thread_id, index);

        Registration {
            index,
            thread_id,
        }
    };
}
<commit_msg>reactor: use LocalKey::try_with in sharded RW lock (#628)<commit_after>//! A scalable reader-writer lock.
//!
//! This implementation makes read operations faster and more scalable due to less contention,
//! while making write operations slower. It also incurs much higher memory overhead than
//! traditional reader-writer locks.

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::Mutex;
use std::thread::{self, ThreadId};

use crossbeam_utils::CachePadded;
use num_cpus;
use parking_lot;

/// A scalable read-writer lock.
///
/// This type of lock allows a number of readers or at most one writer at any point in time. The
/// write portion of this lock typically allows modification of the underlying data (exclusive
/// access) and the read portion of this lock typically allows for read-only access (shared
/// access).
///
/// This reader-writer lock differs from typical implementations in that it internally creates a
/// list of reader-writer locks called 'shards'. Shards are aligned and padded to the cache line
/// size.
///
/// Read operations lock only one shard specific to the current thread, while write operations lock
/// every shard in succession. This strategy makes concurrent read operations faster due to less
/// contention, but write operations are slower due to increased amount of locking.
pub struct RwLock<T> {
    /// A list of locks protecting the internal data.
    shards: Vec<CachePadded<parking_lot::RwLock<()>>>,

    /// The internal data.
    value: UnsafeCell<T>,
}

unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Send + Sync> Sync for RwLock<T> {}

impl<T> RwLock<T> {
    /// Creates a new `RwLock` initialized with `value`.
    pub fn new(value: T) -> RwLock<T> {
        // The number of shards is a power of two so that the modulo operation in `read` becomes a
        // simple bitwise "and".
        let num_shards = num_cpus::get().next_power_of_two();

        RwLock {
            shards: (0..num_shards)
                .map(|_| CachePadded::new(parking_lot::RwLock::new(())))
                .collect(),
            value: UnsafeCell::new(value),
        }
    }

    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be
    /// acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which hold the lock.
    /// There may be other readers currently inside the lock when this method returns. This method
    /// does not provide any guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access once it is dropped.
    pub fn read(&self) -> RwLockReadGuard<T> {
        // Take the current thread index and map it to a shard index. Thread indices will tend to
        // distribute shards among threads equally, thus reducing contention due to read-locking.
        let shard_index = thread_index() & (self.shards.len() - 1);

        RwLockReadGuard {
            parent: self,
            _guard: self.shards[shard_index].read(),
            _marker: PhantomData,
        }
    }

    /// Locks this rwlock with exclusive write access, blocking the current thread until it can be
    /// acquired.
    ///
    /// This function will not return while other writers or other readers currently have access to
    /// the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock when dropped.
    pub fn write(&self) -> RwLockWriteGuard<T> {
        // Write-lock each shard in succession.
        for shard in &self.shards {
            // The write guard is forgotten, but the lock will be manually unlocked in `drop`.
            mem::forget(shard.write());
        }

        RwLockWriteGuard {
            parent: self,
            _marker: PhantomData,
        }
    }
}

/// A guard used to release the shared read access of a `RwLock` when dropped.
pub struct RwLockReadGuard<'a, T: 'a> {
    parent: &'a RwLock<T>,
    _guard: parking_lot::RwLockReadGuard<'a, ()>,
    _marker: PhantomData<parking_lot::RwLockReadGuard<'a, T>>,
}

unsafe impl<'a, T: Sync> Sync for RwLockReadGuard<'a, T> {}

impl<'a, T> Deref for RwLockReadGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.parent.value.get() }
    }
}

/// A guard used to release the exclusive write access of a `RwLock` when dropped.
pub struct RwLockWriteGuard<'a, T: 'a> {
    parent: &'a RwLock<T>,
    _marker: PhantomData<parking_lot::RwLockWriteGuard<'a, T>>,
}

unsafe impl<'a, T: Sync> Sync for RwLockWriteGuard<'a, T> {}

impl<'a, T> Drop for RwLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        // Unlock the shards in reverse order of locking.
        for shard in self.parent.shards.iter().rev() {
            unsafe {
                shard.force_unlock_write();
            }
        }
    }
}

impl<'a, T> Deref for RwLockWriteGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

/// Returns a `usize` that identifies the current thread.
///
/// Each thread is associated with an 'index'. Indices usually tend to be consecutive numbers
/// between 0 and the number of running threads, but there are no guarantees. During TLS teardown
/// the associated index might change.
#[inline]
pub fn thread_index() -> usize {
    REGISTRATION.try_with(|reg| reg.index).unwrap_or(0)
}

/// The global registry keeping track of registered threads and indices.
struct ThreadIndices {
    /// Mapping from `ThreadId` to thread index.
    mapping: HashMap<ThreadId, usize>,

    /// A list of free indices.
    free_list: Vec<usize>,

    /// The next index to allocate if the free list is empty.
    next_index: usize,
}

lazy_static! {
    static ref THREAD_INDICES: Mutex<ThreadIndices> = Mutex::new(ThreadIndices {
        mapping: HashMap::new(),
        free_list: Vec::new(),
        next_index: 0,
    });
}

/// A registration of a thread with an index.
///
/// When dropped, unregisters the thread and frees the reserved index.
struct Registration {
    index: usize,
    thread_id: ThreadId,
}

impl Drop for Registration {
    fn drop(&mut self) {
        let mut indices = THREAD_INDICES.lock().unwrap();
        indices.mapping.remove(&self.thread_id);
        indices.free_list.push(self.index);
    }
}

thread_local! {
    static REGISTRATION: Registration = {
        let thread_id = thread::current().id();
        let mut indices = THREAD_INDICES.lock().unwrap();

        let index = match indices.free_list.pop() {
            Some(i) => i,
            None => {
                let i = indices.next_index;
                indices.next_index += 1;
                i
            }
        };
        indices.mapping.insert(thread_id, index);

        Registration {
            index,
            thread_id,
        }
    };
}
<|endoftext|>


<commit_before>use std::ops::Range;

use askama::Template;

#[derive(Template)]
#[template(path = "for.html")]
struct ForTemplate<'a> {
    strings: Vec<&'a str>,
    tuple_strings: Vec<(&'a str, &'a str)>,
}

#[test]
fn test_for() {
    let s = ForTemplate {
        strings: vec!["A", "alfa", "1"],
        tuple_strings: vec![("B", "beta")],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A (first)\n1. alfa\n2. 1\n\n0. B,beta (first)\n"
    );
}

#[derive(Template)]
#[template(path = "nested-for.html")]
struct NestedForTemplate<'a> {
    seqs: Vec<&'a [&'a str]>,
}

#[test]
fn test_nested_for() {
    let alpha = vec!["a", "b", "c"];
    let numbers = vec!["one", "two"];
    let s = NestedForTemplate {
        seqs: vec![&alpha, &numbers],
    };
    assert_eq!(s.render().unwrap(), "1\n  0a1b2c2\n  0one1two");
}

#[derive(Template)]
#[template(path = "precedence-for.html")]
struct PrecedenceTemplate<'a> {
    strings: Vec<&'a str>,
}

#[test]
fn test_precedence_for() {
    let s = PrecedenceTemplate {
        strings: vec!["A", "alfa", "1"],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A2 (first)\n1. alfa4\n2. 16 (last)\n"
    );
}

#[derive(Template)]
#[template(path = "for-range.html")]
struct ForRangeTemplate {
    init: i32,
    end: i32,
}

#[test]
fn test_for_range() {
    let s = ForRangeTemplate { init: -1, end: 1 };
    assert_eq!(
        s.render().unwrap(),
        "foo (first)\nfoo (last)\nbar\nbar\nfoo\nbar\nbar\n"
    );
}

#[derive(Template)]
#[template(source = "{% for i in [1, 2, 3] %}{{ i }}{% endfor %}", ext = "txt")]
struct ForArrayTemplate;

#[test]
fn test_for_array() {
    let t = ForArrayTemplate;
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3].iter() %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForMethodCallTemplate;

#[test]
fn test_for_method_call() {
    let t = ForMethodCallTemplate;
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in ::std::iter::repeat(\"a\").take(5) %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForPathCallTemplate;

#[test]
fn test_for_path_call() {
    assert_eq!(ForPathCallTemplate.render().unwrap(), "aaaaa");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3, 4, 5][3..] %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForIndexTemplate;

#[test]
fn test_for_index() {
    let t = ForIndexTemplate;
    assert_eq!(t.render().unwrap(), "45");
}

#[derive(Template)]
#[template(
    source = "{% for (i, j) in (0..10).zip(10..20).zip(30..40) %}{{ i.0 }} {{ i.1 }} {{ j }} {% endfor %}",
    ext = "txt"
)]
struct ForZipRangesTemplate;

#[test]
fn test_for_zip_ranges() {
    let t = ForZipRangesTemplate;
    assert_eq!(
        t.render().unwrap(),
        "0 10 30 1 11 31 2 12 32 3 13 33 4 14 34 5 15 35 6 16 36 7 17 37 8 18 38 9 19 39 "
    );
}

struct ForVecAttrVec {
    iterable: Vec<i32>,
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrVecTemplate {
    v: Vec<ForVecAttrVec>,
}

#[test]
fn test_for_vec_attr_vec() {
    let t = ForVecAttrVecTemplate {
        v: vec![
            ForVecAttrVec {
                iterable: vec![1, 2],
            },
            ForVecAttrVec {
                iterable: vec![3, 4],
            },
            ForVecAttrVec {
                iterable: vec![5, 6],
            },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}

struct ForVecAttrSlice {
    iterable: &'static [i32],
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrSliceTemplate {
    v: Vec<ForVecAttrSlice>,
}

#[test]
fn test_for_vec_attr_slice() {
    let t = ForVecAttrSliceTemplate {
        v: vec![
            ForVecAttrSlice { iterable: &[1, 2] },
            ForVecAttrSlice { iterable: &[3, 4] },
            ForVecAttrSlice { iterable: &[5, 6] },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}

struct ForVecAttrRange {
    iterable: Range<usize>,
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable.clone() %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrRangeTemplate {
    v: Vec<ForVecAttrRange>,
}

#[test]
fn test_for_vec_attr_range() {
    let t = ForVecAttrRangeTemplate {
        v: vec![
            ForVecAttrRange { iterable: 1..3 },
            ForVecAttrRange { iterable: 3..5 },
            ForVecAttrRange { iterable: 5..7 },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}
<commit_msg>Add loop variable shadowing test<commit_after>use std::ops::Range;

use askama::Template;

#[derive(Template)]
#[template(path = "for.html")]
struct ForTemplate<'a> {
    strings: Vec<&'a str>,
    tuple_strings: Vec<(&'a str, &'a str)>,
}

#[test]
fn test_for() {
    let s = ForTemplate {
        strings: vec!["A", "alfa", "1"],
        tuple_strings: vec![("B", "beta")],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A (first)\n1. alfa\n2. 1\n\n0. B,beta (first)\n"
    );
}

#[derive(Template)]
#[template(path = "nested-for.html")]
struct NestedForTemplate<'a> {
    seqs: Vec<&'a [&'a str]>,
}

#[test]
fn test_nested_for() {
    let alpha = vec!["a", "b", "c"];
    let numbers = vec!["one", "two"];
    let s = NestedForTemplate {
        seqs: vec![&alpha, &numbers],
    };
    assert_eq!(s.render().unwrap(), "1\n  0a1b2c2\n  0one1two");
}

#[derive(Template)]
#[template(path = "precedence-for.html")]
struct PrecedenceTemplate<'a> {
    strings: Vec<&'a str>,
}

#[test]
fn test_precedence_for() {
    let s = PrecedenceTemplate {
        strings: vec!["A", "alfa", "1"],
    };
    assert_eq!(
        s.render().unwrap(),
        "0. A2 (first)\n1. alfa4\n2. 16 (last)\n"
    );
}

#[derive(Template)]
#[template(path = "for-range.html")]
struct ForRangeTemplate {
    init: i32,
    end: i32,
}

#[test]
fn test_for_range() {
    let s = ForRangeTemplate { init: -1, end: 1 };
    assert_eq!(
        s.render().unwrap(),
        "foo (first)\nfoo (last)\nbar\nbar\nfoo\nbar\nbar\n"
    );
}

#[derive(Template)]
#[template(source = "{% for i in [1, 2, 3] %}{{ i }}{% endfor %}", ext = "txt")]
struct ForArrayTemplate;

#[test]
fn test_for_array() {
    let t = ForArrayTemplate;
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3].iter() %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForMethodCallTemplate;

#[test]
fn test_for_method_call() {
    let t = ForMethodCallTemplate;
    assert_eq!(t.render().unwrap(), "123");
}

#[derive(Template)]
#[template(
    source = "{% for i in ::std::iter::repeat(\"a\").take(5) %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForPathCallTemplate;

#[test]
fn test_for_path_call() {
    assert_eq!(ForPathCallTemplate.render().unwrap(), "aaaaa");
}

#[derive(Template)]
#[template(
    source = "{% for i in [1, 2, 3, 4, 5][3..] %}{{ i }}{% endfor %}",
    ext = "txt"
)]
struct ForIndexTemplate;

#[test]
fn test_for_index() {
    let t = ForIndexTemplate;
    assert_eq!(t.render().unwrap(), "45");
}

#[derive(Template)]
#[template(
    source = "{% for (i, j) in (0..10).zip(10..20).zip(30..40) %}{{ i.0 }} {{ i.1 }} {{ j }} {% endfor %}",
    ext = "txt"
)]
struct ForZipRangesTemplate;

#[test]
fn test_for_zip_ranges() {
    let t = ForZipRangesTemplate;
    assert_eq!(
        t.render().unwrap(),
        "0 10 30 1 11 31 2 12 32 3 13 33 4 14 34 5 15 35 6 16 36 7 17 37 8 18 38 9 19 39 "
    );
}

struct ForVecAttrVec {
    iterable: Vec<i32>,
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrVecTemplate {
    v: Vec<ForVecAttrVec>,
}

#[test]
fn test_for_vec_attr_vec() {
    let t = ForVecAttrVecTemplate {
        v: vec![
            ForVecAttrVec {
                iterable: vec![1, 2],
            },
            ForVecAttrVec {
                iterable: vec![3, 4],
            },
            ForVecAttrVec {
                iterable: vec![5, 6],
            },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}

struct ForVecAttrSlice {
    iterable: &'static [i32],
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrSliceTemplate {
    v: Vec<ForVecAttrSlice>,
}

#[test]
fn test_for_vec_attr_slice() {
    let t = ForVecAttrSliceTemplate {
        v: vec![
            ForVecAttrSlice { iterable: &[1, 2] },
            ForVecAttrSlice { iterable: &[3, 4] },
            ForVecAttrSlice { iterable: &[5, 6] },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}

struct ForVecAttrRange {
    iterable: Range<usize>,
}

#[derive(Template)]
#[template(
    source = "{% for x in v %}{% for y in x.iterable.clone() %}{{ y }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrRangeTemplate {
    v: Vec<ForVecAttrRange>,
}

#[test]
fn test_for_vec_attr_range() {
    let t = ForVecAttrRangeTemplate {
        v: vec![
            ForVecAttrRange { iterable: 1..3 },
            ForVecAttrRange { iterable: 3..5 },
            ForVecAttrRange { iterable: 5..7 },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}

#[derive(Template)]
#[template(
    source = "{% for v in v %}{% let v = v %}{% for v in v.iterable %}{% let v = v %}{{ v }} {% endfor %}{% endfor %}",
    ext = "txt"
)]
struct ForVecAttrSliceShadowingTemplate {
    v: Vec<ForVecAttrSlice>,
}

#[test]
fn test_for_vec_attr_slice_shadowing() {
    let t = ForVecAttrSliceShadowingTemplate {
        v: vec![
            ForVecAttrSlice { iterable: &[1, 2] },
            ForVecAttrSlice { iterable: &[3, 4] },
            ForVecAttrSlice { iterable: &[5, 6] },
        ],
    };
    assert_eq!(t.render().unwrap(), "1 2 3 4 5 6 ");
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    counters::{
        PROCESSED_STRUCT_LOG_COUNT, SENT_STRUCT_LOG_COUNT, STRUCT_LOG_PARSE_ERROR_COUNT,
        STRUCT_LOG_QUEUE_ERROR_COUNT, STRUCT_LOG_SEND_ERROR_COUNT,
    },
    struct_log::TcpWriter,
    Level, StructuredLogEntry,
};
use std::{
    env, fmt,
    io::Write,
    sync::{
        mpsc::{self, Receiver, SyncSender},
        Arc,
    },
    thread,
};

pub const CHANNEL_SIZE: usize = 10000; // MAX_LOG_LINE_SIZE * 10000 = max buffer size
const NUM_SEND_RETRIES: u8 = 1;

pub struct LibraLoggerBuilder {
    channel_size: usize,
    level: Level,
    address: Option<String>,
    printer: Option<Box<dyn Writer>>,
    is_async: bool,
}

impl LibraLoggerBuilder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        Self {
            channel_size: CHANNEL_SIZE,
            level: Level::Debug,
            address: None,
            printer: Some(Box::new(StderrWriter)),
            is_async: false,
        }
    }

    pub fn address(&mut self, address: String) -> &mut Self {
        self.address = Some(address);
        self
    }

    pub fn read_env(&mut self) -> &mut Self {
        if let Ok(address) = env::var("STRUCT_LOG_TCP_ADDR") {
            self.address(address);
        }
        self
    }

    pub fn level(&mut self, level: Level) -> &mut Self {
        self.level = level;
        self
    }

    pub fn channel_size(&mut self, channel_size: usize) -> &mut Self {
        self.channel_size = channel_size;
        self
    }

    pub fn printer(&mut self, printer: Box<dyn Writer + Send + Sync + 'static>) -> &mut Self {
        self.printer = Some(printer);
        self
    }

    pub fn is_async(&mut self, is_async: bool) -> &mut Self {
        self.is_async = is_async;
        self
    }

    pub fn init(&mut self) {
        self.build()
    }

    pub fn build(&mut self) {
        let logger = if self.is_async {
            let (tx, rx) = mpsc::sync_channel(self.channel_size);
            let service = LoggerService {
                rx,
                address: self.address.clone(),
                printer: self.printer.take(),
            };
            let logger = Arc::new(LibraLogger {
                tx: Some(tx),
                printer: None,
                level: self.level,
            });

            thread::spawn(move || service.run());
            logger
        } else {
            Arc::new(LibraLogger {
                tx: None,
                printer: self.printer.take(),
                level: self.level,
            })
        };

        crate::logger::set_global_logger(logger.clone());
        let logger = Box::leak(Box::new(logger));
        crate::struct_log::set_struct_logger(logger).expect("Unable to setup structured logger");
    }
}

pub struct LibraLogger {
    tx: Option<SyncSender<StructuredLogEntry>>,
    printer: Option<Box<dyn Writer>>,
    level: Level,
}

impl LibraLogger {
    pub fn builder() -> LibraLoggerBuilder {
        LibraLoggerBuilder::new()
    }

    #[allow(clippy::new_ret_no_self)]
    pub fn new() -> LibraLoggerBuilder {
        Self::builder()
    }

    pub fn init_for_testing() {
        if env::var("RUST_LOG").is_err() {
            return;
        }

        Self::builder()
            .is_async(false)
            .printer(Box::new(StderrWriter))
            .build()
    }

    fn send_entry(&self, entry: StructuredLogEntry) {
        if let Some(printer) = &self.printer {
            let s = format(&entry).expect("Unable to format");
            printer.write(s);
        }

        if let Some(tx) = &self.tx {
            if let Err(e) = tx.try_send(entry) {
                STRUCT_LOG_QUEUE_ERROR_COUNT.inc();
                eprintln!("Failed to send structured log: {}", e);
            }
        }
    }
}

impl crate::logger::Logger for LibraLogger {
    fn enabled(&self, metadata: &crate::Metadata) -> bool {
        metadata.level() <= self.level
    }

    fn record(&self, event: &crate::Event) {
        let mut entry = StructuredLogEntry::default()
            .level(event.metadata().level())
            .schemas(event.keys_and_values());
        entry
            .add_category(event.metadata().target())
            .add_module(event.metadata().module_path())
            .add_location(event.metadata().location());

        if let Some(message) = event.message() {
            entry = entry.message(message.to_string());
        }

        self.send_entry(entry)
    }
}

impl crate::struct_log::StructLogSink for LibraLogger {
    fn send(&self, entry: StructuredLogEntry) {
        self.send_entry(entry)
    }
}

impl crate::struct_log::StructLogSink for Arc<LibraLogger> {
    fn send(&self, entry: StructuredLogEntry) {
        self.send_entry(entry)
    }
}

struct LoggerService {
    rx: Receiver<StructuredLogEntry>,
    address: Option<String>,
    printer: Option<Box<dyn Writer>>,
}

impl LoggerService {
    pub fn run(mut self) {
        let mut writer = self.address.take().map(TcpWriter::new);

        for entry in self.rx {
            PROCESSED_STRUCT_LOG_COUNT.inc();

            if let Some(writer) = &mut writer {
                Self::write_to_logstash(writer, &entry);
            }

            if let Some(printer) = &self.printer {
                let s = format(&entry).expect("Unable to format");
                printer.write(s)
            }
        }
    }

    /// Writes a log line into json_lines logstash format, which has a newline at the end
    fn write_to_logstash(stream: &mut TcpWriter, entry: &StructuredLogEntry) {
        let message = if let Ok(json) = entry.to_json_string() {
            json
        } else {
            STRUCT_LOG_PARSE_ERROR_COUNT.inc();
            return;
        };

        let message = message + "\n";
        let bytes = message.as_bytes();

        // Attempt to write the log up to NUM_SEND_RETRIES + 1, and then drop it
        // Each `write_all` call will attempt to open a connection if one isn't open
        let mut result = stream.write_all(bytes);
        for _ in 0..NUM_SEND_RETRIES {
            if result.is_ok() {
                break;
            } else {
                result = stream.write_all(bytes);
            }
        }

        if let Err(e) = result {
            STRUCT_LOG_SEND_ERROR_COUNT.inc();
            eprintln!(
                "[Logging] Error while sending data to logstash({}): {}",
                stream.endpoint(),
                e
            );
        } else {
            SENT_STRUCT_LOG_COUNT.inc()
        }
    }
}

/// An trait encapsulating the operations required for writing logs.
pub trait Writer: Send + Sync {
    /// Write the log.
    fn write(&self, log: String);
}

/// A struct for writing logs to stderr
struct StderrWriter;

impl Writer for StderrWriter {
    /// Write log to stderr
    fn write(&self, log: String) {
        eprintln!("{}", log);
    }
}

/// Converts a record into a string representation:
/// UNIX_TIMESTAMP LOG_LEVEL FILE:LINE MESSAGE
/// Example:
/// 2020-03-07 05:03:03 INFO common/libra-logger/src/lib.rs:261 Hello
fn format(entry: &StructuredLogEntry) -> Result<String, fmt::Error> {
    use std::fmt::Write;

    let mut w = String::new();
    if let Some(level) = &entry.level {
        write!(w, "{} ", level)?;
    }

    write!(w, "{} ", entry.timestamp)?;

    if let Some(location) = &entry.location {
        write!(w, "{} ", location)?;
    }

    if let Some(message) = &entry.message {
        write!(w, "{}", message)?;
    }

    Ok(w)
}
<commit_msg>logger: rename tx, rx -> sender, receiver<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    counters::{
        PROCESSED_STRUCT_LOG_COUNT, SENT_STRUCT_LOG_COUNT, STRUCT_LOG_PARSE_ERROR_COUNT,
        STRUCT_LOG_QUEUE_ERROR_COUNT, STRUCT_LOG_SEND_ERROR_COUNT,
    },
    struct_log::TcpWriter,
    Level, StructuredLogEntry,
};
use std::{
    env, fmt,
    io::Write,
    sync::{
        mpsc::{self, Receiver, SyncSender},
        Arc,
    },
    thread,
};

pub const CHANNEL_SIZE: usize = 10000; // MAX_LOG_LINE_SIZE * 10000 = max buffer size
const NUM_SEND_RETRIES: u8 = 1;

pub struct LibraLoggerBuilder {
    channel_size: usize,
    level: Level,
    address: Option<String>,
    printer: Option<Box<dyn Writer>>,
    is_async: bool,
}

impl LibraLoggerBuilder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        Self {
            channel_size: CHANNEL_SIZE,
            level: Level::Debug,
            address: None,
            printer: Some(Box::new(StderrWriter)),
            is_async: false,
        }
    }

    pub fn address(&mut self, address: String) -> &mut Self {
        self.address = Some(address);
        self
    }

    pub fn read_env(&mut self) -> &mut Self {
        if let Ok(address) = env::var("STRUCT_LOG_TCP_ADDR") {
            self.address(address);
        }
        self
    }

    pub fn level(&mut self, level: Level) -> &mut Self {
        self.level = level;
        self
    }

    pub fn channel_size(&mut self, channel_size: usize) -> &mut Self {
        self.channel_size = channel_size;
        self
    }

    pub fn printer(&mut self, printer: Box<dyn Writer + Send + Sync + 'static>) -> &mut Self {
        self.printer = Some(printer);
        self
    }

    pub fn is_async(&mut self, is_async: bool) -> &mut Self {
        self.is_async = is_async;
        self
    }

    pub fn init(&mut self) {
        self.build()
    }

    pub fn build(&mut self) {
        let logger = if self.is_async {
            let (sender, receiver) = mpsc::sync_channel(self.channel_size);
            let service = LoggerService {
                receiver,
                address: self.address.clone(),
                printer: self.printer.take(),
            };
            let logger = Arc::new(LibraLogger {
                sender: Some(sender),
                printer: None,
                level: self.level,
            });

            thread::spawn(move || service.run());
            logger
        } else {
            Arc::new(LibraLogger {
                sender: None,
                printer: self.printer.take(),
                level: self.level,
            })
        };

        crate::logger::set_global_logger(logger.clone());
        let logger = Box::leak(Box::new(logger));
        crate::struct_log::set_struct_logger(logger).expect("Unable to setup structured logger");
    }
}

pub struct LibraLogger {
    sender: Option<SyncSender<StructuredLogEntry>>,
    printer: Option<Box<dyn Writer>>,
    level: Level,
}

impl LibraLogger {
    pub fn builder() -> LibraLoggerBuilder {
        LibraLoggerBuilder::new()
    }

    #[allow(clippy::new_ret_no_self)]
    pub fn new() -> LibraLoggerBuilder {
        Self::builder()
    }

    pub fn init_for_testing() {
        if env::var("RUST_LOG").is_err() {
            return;
        }

        Self::builder()
            .is_async(false)
            .printer(Box::new(StderrWriter))
            .build()
    }

    fn send_entry(&self, entry: StructuredLogEntry) {
        if let Some(printer) = &self.printer {
            let s = format(&entry).expect("Unable to format");
            printer.write(s);
        }

        if let Some(sender) = &self.sender {
            if let Err(e) = sender.try_send(entry) {
                STRUCT_LOG_QUEUE_ERROR_COUNT.inc();
                eprintln!("Failed to send structured log: {}", e);
            }
        }
    }
}

impl crate::logger::Logger for LibraLogger {
    fn enabled(&self, metadata: &crate::Metadata) -> bool {
        metadata.level() <= self.level
    }

    fn record(&self, event: &crate::Event) {
        let mut entry = StructuredLogEntry::default()
            .level(event.metadata().level())
            .schemas(event.keys_and_values());
        entry
            .add_category(event.metadata().target())
            .add_module(event.metadata().module_path())
            .add_location(event.metadata().location());

        if let Some(message) = event.message() {
            entry = entry.message(message.to_string());
        }

        self.send_entry(entry)
    }
}

impl crate::struct_log::StructLogSink for LibraLogger {
    fn send(&self, entry: StructuredLogEntry) {
        self.send_entry(entry)
    }
}

impl crate::struct_log::StructLogSink for Arc<LibraLogger> {
    fn send(&self, entry: StructuredLogEntry) {
        self.send_entry(entry)
    }
}

struct LoggerService {
    receiver: Receiver<StructuredLogEntry>,
    address: Option<String>,
    printer: Option<Box<dyn Writer>>,
}

impl LoggerService {
    pub fn run(mut self) {
        let mut writer = self.address.take().map(TcpWriter::new);

        for entry in self.receiver {
            PROCESSED_STRUCT_LOG_COUNT.inc();

            if let Some(writer) = &mut writer {
                Self::write_to_logstash(writer, &entry);
            }

            if let Some(printer) = &self.printer {
                let s = format(&entry).expect("Unable to format");
                printer.write(s)
            }
        }
    }

    /// Writes a log line into json_lines logstash format, which has a newline at the end
    fn write_to_logstash(stream: &mut TcpWriter, entry: &StructuredLogEntry) {
        let message = if let Ok(json) = entry.to_json_string() {
            json
        } else {
            STRUCT_LOG_PARSE_ERROR_COUNT.inc();
            return;
        };

        let message = message + "\n";
        let bytes = message.as_bytes();

        // Attempt to write the log up to NUM_SEND_RETRIES + 1, and then drop it
        // Each `write_all` call will attempt to open a connection if one isn't open
        let mut result = stream.write_all(bytes);
        for _ in 0..NUM_SEND_RETRIES {
            if result.is_ok() {
                break;
            } else {
                result = stream.write_all(bytes);
            }
        }

        if let Err(e) = result {
            STRUCT_LOG_SEND_ERROR_COUNT.inc();
            eprintln!(
                "[Logging] Error while sending data to logstash({}): {}",
                stream.endpoint(),
                e
            );
        } else {
            SENT_STRUCT_LOG_COUNT.inc()
        }
    }
}

/// An trait encapsulating the operations required for writing logs.
pub trait Writer: Send + Sync {
    /// Write the log.
    fn write(&self, log: String);
}

/// A struct for writing logs to stderr
struct StderrWriter;

impl Writer for StderrWriter {
    /// Write log to stderr
    fn write(&self, log: String) {
        eprintln!("{}", log);
    }
}

/// Converts a record into a string representation:
/// UNIX_TIMESTAMP LOG_LEVEL FILE:LINE MESSAGE
/// Example:
/// 2020-03-07 05:03:03 INFO common/libra-logger/src/lib.rs:261 Hello
fn format(entry: &StructuredLogEntry) -> Result<String, fmt::Error> {
    use std::fmt::Write;

    let mut w = String::new();
    if let Some(level) = &entry.level {
        write!(w, "{} ", level)?;
    }

    write!(w, "{} ", entry.timestamp)?;

    if let Some(location) = &entry.location {
        write!(w, "{} ", location)?;
    }

    if let Some(message) = &entry.message {
        write!(w, "{}", message)?;
    }

    Ok(w)
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

use lexer::Position;

#[derive(Debug)]
pub struct ParsingError {
    description: String,
    err_type: Option<ErrorType>,
    pos: Option<Position>,
}

impl ParsingError {
    pub fn new(description: &str) -> Self {
        ParsingError {
            description: description.into(),
            err_type: None,
            pos: None,
        }
    }

    pub fn position(&mut self, pos: Position) -> &mut Self {
        self.pos = Some(pos);
        self
    }

    pub fn error_type(&mut self, err_type: ErrorType) -> &mut Self {
        self.err_type = Some(err_type);
        self
    }
}

impl fmt::Display for ParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO
        write!(f, "Error")
    }
}

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

#[derive(Debug)]
pub enum ErrorType {
    Catcodes,
}
<commit_msg>make the builder a consuming builder<commit_after>use std::error::Error;
use std::fmt;

use lexer::Position;

#[derive(Debug)]
pub struct ParsingError {
    description: String,
    err_type: Option<ErrorType>,
    pos: Option<Position>,
}

impl ParsingError {
    pub fn new(description: &str) -> Self {
        ParsingError {
            description: description.into(),
            err_type: None,
            pos: None,
        }
    }

    pub fn position(mut self, pos: Position) -> Self {
        self.pos = Some(pos);
        self
    }

    pub fn error_type(mut self, err_type: ErrorType) -> Self {
        self.err_type = Some(err_type);
        self
    }
}

impl fmt::Display for ParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO
        write!(f, "Error")
    }
}

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

#[derive(Debug)]
pub enum ErrorType {
    Catcodes,
}
<|endoftext|>


<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::count_types;
use super::get_types;
use super::get_value;
use super::get_values;
use super::BragiHandler;
use std::path::Path;

pub fn bragi_three_cities_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let mut bragi = BragiHandler::new(es_wrapper.host());
    let out_dir = Path::new(env!("OUT_DIR"));

    // *********************************
    // We load the OSM dataset and three-cities bano dataset
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf (including ways)
    // - bano-three_cities
    // *********************************
    let osm2mimir = out_dir.join("../../../osm2mimir").display().to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-admin".into(),
            "--import-way".into(),
            "--level=8".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let bano2mimir = out_dir.join("../../../bano2mimir").display().to_string();
    crate::launch_and_assert(
        &bano2mimir,
        &[
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let stops2mimir = out_dir.join("../../../stops2mimir").display().to_string();
    crate::launch_and_assert(
        &stops2mimir,
        &[
            "--input=./tests/fixtures/stops_shape.txt".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    three_cities_housenumber_zip_code_test(&mut bragi);
    three_cities_zip_code_test(&mut bragi);
    three_cities_zip_code_address_test(&mut bragi);
    three_cities_shape_test(&mut bragi);
}

fn three_cities_housenumber_zip_code_test(bragi: &mut BragiHandler) {
    // we search for a house number with a postcode, we should be able to find
    // the house number with this number in this city
    let all_20 = bragi.get("/autocomplete?q=3 rue 77255");
    assert_eq!(all_20.len(), 1);
    assert!(get_values(&all_20, "postcode")
        .iter()
        .all(|r| *r == "77255",));
    let types = get_types(&all_20);
    let count = count_types(&types, "street");
    assert_eq!(count, 0);

    let count = count_types(&types, "city");
    assert_eq!(count, 0);

    let count = count_types(&types, "house");
    assert_eq!(count, 1);
    let first_house = all_20.iter().find(|e| get_value(e, "type") == "house");
    assert_eq!(get_value(first_house.unwrap(), "citycode"), "77255");
    assert_eq!(
        get_value(first_house.unwrap(), "label"),
        "3 Rue du Four à Chaux (Livry-sur-Seine)"
    );
}

fn three_cities_zip_code_test(bragi: &mut BragiHandler) {
    // we query with only a zip code, we should be able to find admins,
    // and some street of it (and all on this admin)
    let res = bragi.get("/autocomplete?q=77000");
    assert_eq!(res.len(), 10);
    assert!(get_values(&res, "postcode")
        .iter()
        .all(|r| r.contains("77000"),));
    let types = get_types(&res);
    // since we did not ask for an house number, we should get none
    assert_eq!(count_types(&types, "house"), 0);
}

fn three_cities_zip_code_address_test(bragi: &mut BragiHandler) {
    let all_20 = bragi.get("/autocomplete?q=77288 2 Rue de la Reine Blanche");
    assert_eq!(all_20.len(), 1);
    assert!(get_values(&all_20, "postcode")
        .iter()
        .all(|r| *r == "77288",));
    let types = get_types(&all_20);
    let count = count_types(&types, "street");
    assert_eq!(count, 0);

    let count = count_types(&types, "city");
    assert_eq!(count, 0);

    let count = count_types(&types, "house");
    assert_eq!(count, 1);

    assert_eq!(
        get_values(&all_20, "label"),
        vec!["2 Rue de la Reine Blanche (Melun)"]
    );
}

fn three_cities_shape_test(bragi: &mut BragiHandler) {
    //      A ---------------------D
    //      |                      |
    //      |        === street    |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where street in shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates": [[[2.656546, 48.537227],
        [2.657608, 48.537244],[2.657340, 48.536602],[2.656476, 48.536545],[2.656546, 48.537227]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(
        get_values(&geocodings, "label"),
        vec!["Rue du Port (Melun)"]
    );

    //      A ---------------------D
    //      |                      |
    //      |                      | === street
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where street outside shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 68.537227],
        [2.657608, 68.537244],[2.657340, 68.536602],[2.656476, 68.536545],[2.656546, 68.537227]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 0);

    //      A ---------------------D
    //      |                      |
    //      |        X Melun       |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where admin in shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 48.538927]
        ,[2.670816, 48.538927],[2.676476, 48.546545],[2.656546, 48.546545],[2.656546, 48.538927]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Melun", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "name"), vec!["Melun"]);

    //      A ---------------------D
    //      |                      |
    //      |                      | X Melun
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where admin outside shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 66.538927],
        [2.670816, 68.538927],[2.676476, 68.546545],[2.656546, 68.546545],[2.656546, 66.538927]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Melun", shape);
    assert_eq!(geocodings.len(), 0);

    // shape filtering does not apply to stop areas.
    //
    //      A ---------------------D                 48.5372
    //      |                      |
    //      |      ===== street1   | ==== street2
    //      |                      |
    //      |      O stop1         | O stop2
    //      B ---------------------C                 48.5366
    //
    //      2.6565                 2.6576
    //
    // Search with shape and stops, we should have, based on the diagram:
    // - street1 visible     (because within shape)
    // - stop1 visible       (because within shape)
    // - street2 not visible (because outside of shape)
    // - stop2 visible       (because type=stop area)
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates": [[[2.6565, 48.5372],
        [2.6576, 48.5372],[2.6573, 48.5366],[2.6564, 48.5365],[2.6565, 48.5372]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(
        get_values(&geocodings, "label"),
        vec!["Rue du Port (Melun)"]
    );

    let geocodings = bragi.post("/autocomplete?q=Stop In&_all_data=true", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "label"), vec!["Stop In (Melun)"]);

    let geocodings = bragi.post("/autocomplete?q=Stop Out&_all_data=true", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "label"), vec!["Stop Out (Melun)"]);

    let geocodings = bragi.post("/autocomplete?q=Four", shape);
    assert_eq!(geocodings.len(), 0);
}
<commit_msg>Add a check to shape filtering<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::count_types;
use super::get_types;
use super::get_value;
use super::get_values;
use super::BragiHandler;
use std::path::Path;

pub fn bragi_three_cities_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let mut bragi = BragiHandler::new(es_wrapper.host());
    let out_dir = Path::new(env!("OUT_DIR"));

    // *********************************
    // We load the OSM dataset and three-cities bano dataset
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf (including ways)
    // - bano-three_cities
    // *********************************
    let osm2mimir = out_dir.join("../../../osm2mimir").display().to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-admin".into(),
            "--import-way".into(),
            "--level=8".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let bano2mimir = out_dir.join("../../../bano2mimir").display().to_string();
    crate::launch_and_assert(
        &bano2mimir,
        &[
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let stops2mimir = out_dir.join("../../../stops2mimir").display().to_string();
    crate::launch_and_assert(
        &stops2mimir,
        &[
            "--input=./tests/fixtures/stops_shape.txt".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    three_cities_housenumber_zip_code_test(&mut bragi);
    three_cities_zip_code_test(&mut bragi);
    three_cities_zip_code_address_test(&mut bragi);
    three_cities_shape_test(&mut bragi);
}

fn three_cities_housenumber_zip_code_test(bragi: &mut BragiHandler) {
    // we search for a house number with a postcode, we should be able to find
    // the house number with this number in this city
    let all_20 = bragi.get("/autocomplete?q=3 rue 77255");
    assert_eq!(all_20.len(), 1);
    assert!(get_values(&all_20, "postcode")
        .iter()
        .all(|r| *r == "77255",));
    let types = get_types(&all_20);
    let count = count_types(&types, "street");
    assert_eq!(count, 0);

    let count = count_types(&types, "city");
    assert_eq!(count, 0);

    let count = count_types(&types, "house");
    assert_eq!(count, 1);
    let first_house = all_20.iter().find(|e| get_value(e, "type") == "house");
    assert_eq!(get_value(first_house.unwrap(), "citycode"), "77255");
    assert_eq!(
        get_value(first_house.unwrap(), "label"),
        "3 Rue du Four à Chaux (Livry-sur-Seine)"
    );
}

fn three_cities_zip_code_test(bragi: &mut BragiHandler) {
    // we query with only a zip code, we should be able to find admins,
    // and some street of it (and all on this admin)
    let res = bragi.get("/autocomplete?q=77000");
    assert_eq!(res.len(), 10);
    assert!(get_values(&res, "postcode")
        .iter()
        .all(|r| r.contains("77000"),));
    let types = get_types(&res);
    // since we did not ask for an house number, we should get none
    assert_eq!(count_types(&types, "house"), 0);
}

fn three_cities_zip_code_address_test(bragi: &mut BragiHandler) {
    let all_20 = bragi.get("/autocomplete?q=77288 2 Rue de la Reine Blanche");
    assert_eq!(all_20.len(), 1);
    assert!(get_values(&all_20, "postcode")
        .iter()
        .all(|r| *r == "77288",));
    let types = get_types(&all_20);
    let count = count_types(&types, "street");
    assert_eq!(count, 0);

    let count = count_types(&types, "city");
    assert_eq!(count, 0);

    let count = count_types(&types, "house");
    assert_eq!(count, 1);

    assert_eq!(
        get_values(&all_20, "label"),
        vec!["2 Rue de la Reine Blanche (Melun)"]
    );
}

fn three_cities_shape_test(bragi: &mut BragiHandler) {
    //      A ---------------------D
    //      |                      |
    //      |        === street    |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where street in shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates": [[[2.656546, 48.537227],
        [2.657608, 48.537244],[2.657340, 48.536602],[2.656476, 48.536545],[2.656546, 48.537227]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(
        get_values(&geocodings, "label"),
        vec!["Rue du Port (Melun)"]
    );

    //      A ---------------------D
    //      |                      |
    //      |                      | === street
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where street outside shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 68.537227],
        [2.657608, 68.537244],[2.657340, 68.536602],[2.656476, 68.536545],[2.656546, 68.537227]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 0);

    //      A ---------------------D
    //      |                      |
    //      |        X Melun       |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where admin in shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 48.538927]
        ,[2.670816, 48.538927],[2.676476, 48.546545],[2.656546, 48.546545],[2.656546, 48.538927]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Melun", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "name"), vec!["Melun"]);

    //      A ---------------------D
    //      |                      |
    //      |                      | X Melun
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where admin outside shape
    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates":[[[2.656546, 66.538927],
        [2.670816, 68.538927],[2.676476, 68.546545],[2.656546, 68.546545],[2.656546, 66.538927]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Melun", shape);
    assert_eq!(geocodings.len(), 0);

    // shape filtering does not apply to stop areas.
    //
    //      A ---------------------D                 48.5372
    //      |                      |
    //      |      ===== street1   | ==== street2
    //      |                      |
    //      |      O stop1         | O stop2
    //      B ---------------------C                 48.5366
    //
    //      2.6565                 2.6576
    //
    // Search with shape and stops, we should have, based on the diagram:
    // - street1 visible     (because within shape)
    // - stop1 visible       (because within shape)
    // - street2 not visible (because outside of shape)
    // - stop2 visible       (because type=stop area)
    //
    // We also want to make sure street2 is visible if we don't use shape filtering

    let shape = r#"{"shape": {"type": "Feature","properties":{},"geometry":{"type":"Polygon",
        "coordinates": [[[2.6565, 48.5372],
        [2.6576, 48.5372],[2.6573, 48.5366],[2.6564, 48.5365],[2.6565, 48.5372]]]}}}"#;

    let geocodings = bragi.post("/autocomplete?q=Rue du Port", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(
        get_values(&geocodings, "label"),
        vec!["Rue du Port (Melun)"]
    );

    let geocodings = bragi.post("/autocomplete?q=Stop In&_all_data=true", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "label"), vec!["Stop In (Melun)"]);

    let geocodings = bragi.post("/autocomplete?q=Stop Out&_all_data=true", shape);
    assert_eq!(geocodings.len(), 1);
    assert_eq!(get_values(&geocodings, "label"), vec!["Stop Out (Melun)"]);

    let geocodings = bragi.post("/autocomplete?q=Four", shape);
    assert_eq!(geocodings.len(), 0);

    let geocodings = bragi.get("/autocomplete?q=Four");
    assert_eq!(geocodings.len(), 1);
    assert_eq!(
        get_values(&geocodings, "label"),
        vec!["Rue du Four à Chaux (Livry-sur-Seine)"]
    );
}
<|endoftext|>


<commit_before>use std::ops::{Add, BitAnd, BitXor, Div, Mul, Shr, Sub};
use num::{BigUint, One, Zero};

const BITS: usize = 255;
const BYTES: usize = (BITS + 7) / 8;
const A24: u32 = 121665;

/// After geting a shared secret, make sure to abort if it's 0
pub fn gen_pk(sk: &[u8]) -> Vec<u8> {
    let mut u = [0; 32];
    u[0] = 9;
    x25519(sk, &u)
}

/// This is horrible
/// and insecure
pub fn x25519(k: &[u8], u: &[u8]) -> Vec<u8> {
    assert_eq!(BYTES, k.len());
    assert_eq!(BYTES, u.len());
    let k = decode_scalar(k);
    let x_1 = decode_u_coordinate(u);
    let mut x_2 = One::one();
    let mut z_2 = Zero::zero();
    let mut x_3 = x_1.clone();
    let mut z_3 = One::one();
    let mut swap = Zero::zero();
    let a24 = Field::new(A24.into());

    for t in (0..BITS).rev() {
        let k_t = &(&k >> t) & &One::one();
        swap = &swap ^ &k_t;
        cswap(&swap, &mut x_2, &mut x_3);
        cswap(&swap, &mut z_2, &mut z_3);
        swap = k_t;

        let a = &x_2 + &z_2;
        let aa = &a * &a;
        let b = &x_2 - &z_2;
        let bb = &b * &b;
        let e = &aa - &bb;
        let c = &x_3 + &z_3;
        let d = &x_3 - &z_3;
        let da = d * a;
        let cb = c * b;
        x_3 = &da + &cb;
        x_3 = &x_3 * &x_3;
        z_3 = &da - &cb;
        z_3 = &x_1 * &(&z_3 * &z_3);
        x_2 = &aa * &bb;
        z_2 = &e * &(aa + &a24 * &e);
    }
    cswap(&swap, &mut x_2, &mut x_3);
    cswap(&swap, &mut z_2, &mut z_3);
    (&x_2 / &z_2).to_bytes()
}

#[derive(Debug, PartialEq, Eq, Clone)]
struct Field {
    x: BigUint,
    p: BigUint,
}

impl Field {
    fn new(x: BigUint) -> Self {
        let p = (BigUint::from(1u8) << 255) - BigUint::from(19u8);
        Self { x: x % &p, p: p }
    }

    fn inv(&self) -> Self {
        Self::new(pow(&self.x, &self.p - BigUint::from(2u8), &self.p))
    }

    fn from_bytes(bytes: &[u8]) -> Self {
        Field::new(BigUint::from_bytes_le(bytes))
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut x = self.x.to_bytes_le();
        while x.len() < BYTES {
            x.push(0);
        }
        x
    }
}

impl Add for Field {
    type Output = Field;

    fn add(self, rhs: Self) -> Self::Output {
        Self::new(self.x + rhs.x)
    }
}

impl Mul for Field {
    type Output = Field;

    fn mul(self, rhs: Self) -> Self::Output {
        Self::new(self.x * rhs.x)
    }
}

impl<'a, 'b> Add<&'a Field> for &'b Field {
    type Output = Field;

    fn add(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x + &rhs.x)
    }
}

impl<'a, 'b> Sub<&'a Field> for &'b Field {
    type Output = Field;

    fn sub(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.p + &self.x - &rhs.x)
    }
}

impl<'a, 'b> Mul<&'a Field> for &'b Field {
    type Output = Field;

    fn mul(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x * &rhs.x)
    }
}

impl<'a, 'b> Div<&'a Field> for &'b Field {
    type Output = Field;

    fn div(self, rhs: &'a Field) -> Self::Output {
        self * &rhs.inv()
    }
}

impl<'a, 'b> BitAnd<&'a Field> for &'b Field {
    type Output = Field;

    fn bitand(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x & &rhs.x)
    }
}

impl<'a, 'b> BitXor<&'a Field> for &'b Field {
    type Output = Field;

    fn bitxor(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x ^ &rhs.x)
    }
}

impl<'a> Shr<usize> for &'a Field {
    type Output = Field;

    fn shr(self, rhs: usize) -> Self::Output {
        Field::new(&self.x >> rhs)
    }
}

impl One for Field {
    fn one() -> Self {
        Field::new(One::one())
    }
}

impl Zero for Field {
    fn zero() -> Self {
        Field::new(Zero::zero())
    }

    fn is_zero(&self) -> bool {
        self.x.is_zero()
    }
}

fn decode_u_coordinate(u: &[u8]) -> Field {
    let mut u_vec = u.to_vec();
    if BITS % 8 != 0 {
        if let Some(last) = u_vec.last_mut() {
            *last &= (1 << (BITS % 8)) - 1;
        }
    }
    Field::from_bytes(&u_vec)
}

fn decode_scalar(k: &[u8]) -> Field {
    let mut k_vec = k.to_vec();
    k_vec[0] &= 248;
    k_vec[31] &= 127;
    k_vec[31] |= 64;
    Field::from_bytes(&k_vec)
}

fn cswap(swap: &Field, x_2: &mut Field, x_3: &mut Field) {
    let dummy = Field::new(mask(&swap.x) & (&x_2.x ^ &x_3.x));
    *x_2 = &*x_2 ^ &dummy;
    *x_3 = &*x_3 ^ &dummy;
}

fn mask(swap: &BigUint) -> BigUint {
    (BigUint::from(1u8) << 255) - swap
}

fn pow(z: &BigUint, e: BigUint, p: &BigUint) -> BigUint {
    let zero = Zero::zero();
    let one: BigUint = One::one();
    let two: BigUint = 2u8.into();
    let mut res = One::one();
    let mut base = z.clone();
    let mut exponent = e;
    while exponent > zero {
        if &exponent % &two == one {
            res = res * &base % p;
        }
        exponent = exponent >> 1;
        base = &base * &base % p;
    }
    res
}

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

    fn check(x: &str, k: &str, u: &str) {
        assert_eq!(h2b(x), x25519(&h2b(k), &h2b(u)));
    }

    fn check_decode(k: &str, u: &str, k10: &str, u10: &str) {
        assert_eq!(
            Field::new(BigUint::parse_bytes(k10.as_bytes(), 10).unwrap()),
            decode_scalar(&h2b(k))
        );
        assert_eq!(
            Field::new(BigUint::parse_bytes(u10.as_bytes(), 10).unwrap()),
            decode_u_coordinate(&h2b(u))
        );
    }

    #[test]
    fn test_x25519() {
        let mut k = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4";
        let mut u = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c";
        let mut x = "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552";
        check(x, k, u);

        let mut k10;
        let mut u10;
        k10 = "31029842492115040904895560451863089656472772604678260265531221036453811406496";
        u10 = "34426434033919594451155107781188821651316167215306631574996226621102155684838";
        check_decode(k, u, k10, u10);

        k = "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d";
        u = "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493";
        x = "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957";
        check(x, k, u);

        k10 = "35156891815674817266734212754503633747128614016119564763269015315466259359304";
        u10 = "8883857351183929894090759386610649319417338800022198945255395922347792736741";
        check_decode(k, u, k10, u10);

        let mut k = h2b(
            "0900000000000000000000000000000000000000000000000000000000000000",
        );
        let mut u = k.clone();
        // too slow to do 1 mil iterations right now, or 1000 without --release
        for i in 0..1 {
            let x = x25519(&k, &u);
            if i == 0 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999999 {
                assert_eq!(
                    h2b(
                        "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
                    ),
                    x
                );
            }
            u = k;
            k = x;
        }
    }

    #[test]
    fn test_gen_pk() {
        let sk_a = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
        let pk_a = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
        let sk_b = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
        let pk_b = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
        let k = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
        assert_eq!(h2b(pk_a), gen_pk(&h2b(sk_a)));
        assert_eq!(h2b(pk_b), gen_pk(&h2b(sk_b)));
        check(k, sk_a, pk_b);
        check(k, sk_b, pk_a);
    }
}
<commit_msg>curve25519: make p static<commit_after>use std::ops::{Add, BitAnd, BitXor, Div, Mul, Shr, Sub};
use num::{BigUint, One, Zero};

const BITS: usize = 255;
const BYTES: usize = (BITS + 7) / 8;
const A24: u32 = 121665;

lazy_static! {
    static ref P: BigUint = (BigUint::from(1u8) << BITS) - BigUint::from(19u8);
}

/// After geting a shared secret, make sure to abort if it's 0
pub fn gen_pk(sk: &[u8]) -> Vec<u8> {
    let mut u = [0; 32];
    u[0] = 9;
    x25519(sk, &u)
}

/// This is horrible
/// and insecure
pub fn x25519(k: &[u8], u: &[u8]) -> Vec<u8> {
    assert_eq!(BYTES, k.len());
    assert_eq!(BYTES, u.len());
    let k = decode_scalar(k);
    let x_1 = decode_u_coordinate(u);
    let mut x_2 = One::one();
    let mut z_2 = Zero::zero();
    let mut x_3 = x_1.clone();
    let mut z_3 = One::one();
    let mut swap = Zero::zero();
    let a24 = Field::new(A24.into());

    for t in (0..BITS).rev() {
        let k_t = &(&k >> t) & &One::one();
        swap = &swap ^ &k_t;
        cswap(&swap, &mut x_2, &mut x_3);
        cswap(&swap, &mut z_2, &mut z_3);
        swap = k_t;

        let a = &x_2 + &z_2;
        let aa = &a * &a;
        let b = &x_2 - &z_2;
        let bb = &b * &b;
        let e = &aa - &bb;
        let c = &x_3 + &z_3;
        let d = &x_3 - &z_3;
        let da = d * a;
        let cb = c * b;
        x_3 = &da + &cb;
        x_3 = &x_3 * &x_3;
        z_3 = &da - &cb;
        z_3 = &x_1 * &(&z_3 * &z_3);
        x_2 = &aa * &bb;
        z_2 = &e * &(aa + &a24 * &e);
    }
    cswap(&swap, &mut x_2, &mut x_3);
    cswap(&swap, &mut z_2, &mut z_3);
    (&x_2 / &z_2).to_bytes()
}

#[derive(Debug, PartialEq, Eq, Clone)]
struct Field {
    x: BigUint,
}

impl Field {
    fn new(x: BigUint) -> Self {
        Self { x: x % &*P }
    }

    fn inv(&self) -> Self {
        Self::new(pow(&self.x, &*P - BigUint::from(2u8), &*P))
    }

    fn from_bytes(bytes: &[u8]) -> Self {
        Field::new(BigUint::from_bytes_le(bytes))
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut x = self.x.to_bytes_le();
        while x.len() < BYTES {
            x.push(0);
        }
        x
    }
}

impl Add for Field {
    type Output = Field;

    fn add(self, rhs: Self) -> Self::Output {
        Self::new(self.x + rhs.x)
    }
}

impl Mul for Field {
    type Output = Field;

    fn mul(self, rhs: Self) -> Self::Output {
        Self::new(self.x * rhs.x)
    }
}

impl<'a, 'b> Add<&'a Field> for &'b Field {
    type Output = Field;

    fn add(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x + &rhs.x)
    }
}

impl<'a, 'b> Sub<&'a Field> for &'b Field {
    type Output = Field;

    fn sub(self, rhs: &'a Field) -> Self::Output {
        Field::new(&*P + &self.x - &rhs.x)
    }
}

impl<'a, 'b> Mul<&'a Field> for &'b Field {
    type Output = Field;

    fn mul(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x * &rhs.x)
    }
}

impl<'a, 'b> Div<&'a Field> for &'b Field {
    type Output = Field;

    fn div(self, rhs: &'a Field) -> Self::Output {
        self * &rhs.inv()
    }
}

impl<'a, 'b> BitAnd<&'a Field> for &'b Field {
    type Output = Field;

    fn bitand(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x & &rhs.x)
    }
}

impl<'a, 'b> BitXor<&'a Field> for &'b Field {
    type Output = Field;

    fn bitxor(self, rhs: &'a Field) -> Self::Output {
        Field::new(&self.x ^ &rhs.x)
    }
}

impl<'a> Shr<usize> for &'a Field {
    type Output = Field;

    fn shr(self, rhs: usize) -> Self::Output {
        Field::new(&self.x >> rhs)
    }
}

impl One for Field {
    fn one() -> Self {
        Field::new(One::one())
    }
}

impl Zero for Field {
    fn zero() -> Self {
        Field::new(Zero::zero())
    }

    fn is_zero(&self) -> bool {
        self.x.is_zero()
    }
}

fn decode_u_coordinate(u: &[u8]) -> Field {
    let mut u_vec = u.to_vec();
    if BITS % 8 != 0 {
        if let Some(last) = u_vec.last_mut() {
            *last &= (1 << (BITS % 8)) - 1;
        }
    }
    Field::from_bytes(&u_vec)
}

fn decode_scalar(k: &[u8]) -> Field {
    let mut k_vec = k.to_vec();
    k_vec[0] &= 248;
    k_vec[31] &= 127;
    k_vec[31] |= 64;
    Field::from_bytes(&k_vec)
}

fn cswap(swap: &Field, x_2: &mut Field, x_3: &mut Field) {
    let dummy = Field::new(mask(&swap.x) & (&x_2.x ^ &x_3.x));
    *x_2 = &*x_2 ^ &dummy;
    *x_3 = &*x_3 ^ &dummy;
}

fn mask(swap: &BigUint) -> BigUint {
    (BigUint::from(1u8) << 255) - swap
}

fn pow(z: &BigUint, e: BigUint, p: &BigUint) -> BigUint {
    let zero = Zero::zero();
    let one: BigUint = One::one();
    let two: BigUint = 2u8.into();
    let mut res = One::one();
    let mut base = z.clone();
    let mut exponent = e;
    while exponent > zero {
        if &exponent % &two == one {
            res = res * &base % p;
        }
        exponent = exponent >> 1;
        base = &base * &base % p;
    }
    res
}

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

    fn check(x: &str, k: &str, u: &str) {
        assert_eq!(h2b(x), x25519(&h2b(k), &h2b(u)));
    }

    fn check_decode(k: &str, u: &str, k10: &str, u10: &str) {
        assert_eq!(
            Field::new(BigUint::parse_bytes(k10.as_bytes(), 10).unwrap()),
            decode_scalar(&h2b(k))
        );
        assert_eq!(
            Field::new(BigUint::parse_bytes(u10.as_bytes(), 10).unwrap()),
            decode_u_coordinate(&h2b(u))
        );
    }

    #[test]
    fn test_x25519() {
        let mut k = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4";
        let mut u = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c";
        let mut x = "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552";
        check(x, k, u);

        let mut k10;
        let mut u10;
        k10 = "31029842492115040904895560451863089656472772604678260265531221036453811406496";
        u10 = "34426434033919594451155107781188821651316167215306631574996226621102155684838";
        check_decode(k, u, k10, u10);

        k = "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d";
        u = "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493";
        x = "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957";
        check(x, k, u);

        k10 = "35156891815674817266734212754503633747128614016119564763269015315466259359304";
        u10 = "8883857351183929894090759386610649319417338800022198945255395922347792736741";
        check_decode(k, u, k10, u10);

        let mut k = h2b(
            "0900000000000000000000000000000000000000000000000000000000000000",
        );
        let mut u = k.clone();
        // too slow to do 1 mil iterations right now, or 1000 without --release
        for i in 0..1 {
            let x = x25519(&k, &u);
            if i == 0 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999999 {
                assert_eq!(
                    h2b(
                        "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
                    ),
                    x
                );
            }
            u = k;
            k = x;
        }
    }

    #[test]
    fn test_gen_pk() {
        let sk_a = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
        let pk_a = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
        let sk_b = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
        let pk_b = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
        let k = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
        assert_eq!(h2b(pk_a), gen_pk(&h2b(sk_a)));
        assert_eq!(h2b(pk_b), gen_pk(&h2b(sk_b)));
        check(k, sk_a, pk_b);
        check(k, sk_b, pk_a);
    }
}
<|endoftext|>


<commit_before>use pos::Pos;
use std::collections::HashMap;
use std::fmt;
use syntax::Ty;

#[derive(Clone, Debug)]
pub enum Diagnostic<'e, 't> {
  CannotUnifyTypes(Pos, HashMap<&'e str, &'t Ty<'t>>, &'t Ty<'t>, &'t Ty<'t>),
  ValueIsNotInScope(Pos, HashMap<&'e str, &'t Ty<'t>>, &'e str),
  TypeIsNotInScope(Pos, HashMap<&'t str, &'t Ty<'t>>, &'t str),
  HigherRankTypesAreNotSupported(Pos),
}

impl<'e, 't> Diagnostic<'e, 't> {
  pub fn pos(&self) -> Pos {
    match self {
      &Diagnostic::CannotUnifyTypes(p, _, _, _) => p,
      &Diagnostic::ValueIsNotInScope(p, _, _) => p,
      &Diagnostic::TypeIsNotInScope(p, _, _) => p,
      &Diagnostic::HigherRankTypesAreNotSupported(p) => p,
    }
  }

  pub fn fmt<Purge, W>(&self, purge: &Purge, w: &mut W) -> fmt::Result
    where
      Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t>,
      W: fmt::Write {
    write!(w, "{}: ", self.pos().offset())?;
    self.fmt_summary(purge, w)?;
    Ok(())
  }

  fn fmt_summary<Purge, W>(&self, purge: &Purge, w: &mut W) -> fmt::Result
    where
      Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t>,
      W: fmt::Write {
    match self {
      &Diagnostic::CannotUnifyTypes(_, _, t, u) => {
        write!(w, "cannot unify types `")?;
        t.pretty(purge, w)?;
        write!(w, "` and `")?;
        u.pretty(purge, w)?;
        write!(w, "`")?;
        Ok(())
      },
      &Diagnostic::ValueIsNotInScope(_, _, n) =>
        write!(w, "value `{}` is not in scope", n),
      &Diagnostic::TypeIsNotInScope(_, _, n) =>
        write!(w, "type `{}` is not in scope", n),
      &Diagnostic::HigherRankTypesAreNotSupported(_) =>
        write!(w, "higher-rank types are not supported"),
    }
  }

  pub fn fmt_string<Purge>(&self, purge: &Purge) -> String
    where Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t> {
    let mut s = String::new();
    self.fmt(purge, &mut s).unwrap();
    s
  }
}
<commit_msg>Display environment in type errors<commit_after>use pos::Pos;
use std::collections::HashMap;
use std::fmt;
use syntax::Ty;

#[derive(Clone, Debug)]
pub enum Diagnostic<'e, 't> {
  CannotUnifyTypes(Pos, HashMap<&'e str, &'t Ty<'t>>, &'t Ty<'t>, &'t Ty<'t>),
  ValueIsNotInScope(Pos, HashMap<&'e str, &'t Ty<'t>>, &'e str),
  TypeIsNotInScope(Pos, HashMap<&'t str, &'t Ty<'t>>, &'t str),
  HigherRankTypesAreNotSupported(Pos),
}

impl<'e, 't> Diagnostic<'e, 't> {
  pub fn pos(&self) -> Pos {
    match self {
      &Diagnostic::CannotUnifyTypes(p, _, _, _) => p,
      &Diagnostic::ValueIsNotInScope(p, _, _) => p,
      &Diagnostic::TypeIsNotInScope(p, _, _) => p,
      &Diagnostic::HigherRankTypesAreNotSupported(p) => p,
    }
  }

  pub fn env(&self) -> Option<&HashMap<&'e str, &'t Ty<'t>>> {
    match self {
      &Diagnostic::CannotUnifyTypes(_, ref e, _, _) => Some(e),
      &Diagnostic::ValueIsNotInScope(_, ref e, _) => Some(e),
      &Diagnostic::TypeIsNotInScope(_, _, _) => None,
      &Diagnostic::HigherRankTypesAreNotSupported(_) => None,
    }
  }

  pub fn fmt<Purge, W>(&self, purge: &Purge, w: &mut W) -> fmt::Result
    where
      Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t>,
      W: fmt::Write {
    write!(w, "{}: ", self.pos().offset())?;
    self.fmt_summary(purge, w)?;
    for env in self.env() {
      write!(w, "\n\n")?;
      self.fmt_env(purge, env, w)?;
    }
    Ok(())
  }

  fn fmt_summary<Purge, W>(&self, purge: &Purge, w: &mut W) -> fmt::Result
    where
      Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t>,
      W: fmt::Write {
    match self {
      &Diagnostic::CannotUnifyTypes(_, _, t, u) => {
        write!(w, "cannot unify types `")?;
        t.pretty(purge, w)?;
        write!(w, "` and `")?;
        u.pretty(purge, w)?;
        write!(w, "`")?;
        Ok(())
      },
      &Diagnostic::ValueIsNotInScope(_, _, n) =>
        write!(w, "value `{}` is not in scope", n),
      &Diagnostic::TypeIsNotInScope(_, _, n) =>
        write!(w, "type `{}` is not in scope", n),
      &Diagnostic::HigherRankTypesAreNotSupported(_) =>
        write!(w, "higher-rank types are not supported"),
    }
  }

  fn fmt_env<Purge, W>(
    &self,
    purge: &Purge,
    env: &HashMap<&str, &'t Ty<'t>>,
    w: &mut W,
  ) -> fmt::Result
    where
      Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t>,
      W: fmt::Write {
    write!(w, "  Where:\n");
    for (k, v) in env {
      write!(w, "\n    {}\t: ", k);
      v.pretty(purge, w)?;
    }
    Ok(())
  }

  pub fn fmt_string<Purge>(&self, purge: &Purge) -> String
    where Purge: Fn(&'t Ty<'t>) -> &'t Ty<'t> {
    let mut s = String::new();
    self.fmt(purge, &mut s).unwrap();
    s
  }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::fs::remove_dir_all;
use std::rc::Rc;

use paths::Paths;
use reporter::report;

pub struct Downloader {
   paths: Rc<Paths>,
}

impl Downloader {
   pub fn new(paths: Rc<Paths>) -> Self {
      Downloader {
         paths: paths,
      }
   }

   pub fn download(&self) {
      report("Downloading", format!("nginx v{}", self.paths.version));

      if self.paths.already_downloaded() {
         report("Downloaded", "already");
      } else {
         self.download_with_curl();
      }

      if self.paths.already_extracted() {
         self.remove_existing_extract_path();
      }

      self.extract();
   }

   fn download_with_curl(&self) {
      let args = ["-s", "-L", "-O", self.paths.http_location.as_slice()];

      Command::new("curl").args(&args).current_dir(&self.paths.download_path).output().unwrap_or_else(|e| {
         panic!("Downloading nginx with Curl failed: {}.", e)
      });
   }

   fn extract(&self) {
      report("Extracting", "nginx");

      let args = ["xzf", self.paths.archive.as_slice()];

      Command::new("tar").args(&args).current_dir(&self.paths.download_path).output().unwrap_or_else(|e| {
         panic!("Extracting nginx failed: {}.", e)
      });
   }

   fn remove_existing_extract_path(&self) {
      report("Removing", "previously extracted archive");

      remove_dir_all(&self.paths.extract_path).unwrap_or_else(|e| {
         panic!("Cannot delete nginx extract path - {:?}: {}.", self.paths.extract_path, e)
      });
   }
}
<commit_msg>Curl stdout message.<commit_after>use std::process::Command;
use std::fs::remove_dir_all;
use std::rc::Rc;

use paths::Paths;
use reporter::report;

pub struct Downloader {
   paths: Rc<Paths>,
}

impl Downloader {
   pub fn new(paths: Rc<Paths>) -> Self {
      Downloader {
         paths: paths,
      }
   }

   pub fn download(&self) {
      report("Downloading", format!("nginx v{}", self.paths.version));

      if self.paths.already_downloaded() {
         report("Downloaded", "already");
      } else {
         self.download_with_curl();
      }

      if self.paths.already_extracted() {
         self.remove_existing_extract_path();
      }

      self.extract();
   }

   fn download_with_curl(&self) {
      report("Curl", self.paths.http_location.as_slice());

      let args = ["-s", "-L", "-O", self.paths.http_location.as_slice()];

      Command::new("curl").args(&args).current_dir(&self.paths.download_path).output().unwrap_or_else(|e| {
         panic!("Downloading nginx with Curl failed: {}.", e)
      });
   }

   fn extract(&self) {
      report("Extracting", "nginx");

      let args = ["xzf", self.paths.archive.as_slice()];

      Command::new("tar").args(&args).current_dir(&self.paths.download_path).output().unwrap_or_else(|e| {
         panic!("Extracting nginx failed: {}.", e)
      });
   }

   fn remove_existing_extract_path(&self) {
      report("Removing", "previously extracted archive");

      remove_dir_all(&self.paths.extract_path).unwrap_or_else(|e| {
         panic!("Cannot delete nginx extract path - {:?}: {}.", self.paths.extract_path, e)
      });
   }
}
<|endoftext|>