<commit_before>use blip_buf::BlipBuf;
use cpal;
use std;

macro_rules! try_opt {
     ( $expr:expr ) => {
         match $expr {
             Some(v) => v,
             None => return None,
         }
     }
}

pub struct Sound {
    waveram: [u8; 16],
    channel3_on: bool,
    channel3_len: u8,
    channel3_vol: u8,
    channel3_freq: u32,
    channel3_freq_div: u32,
    channel3_uselen: bool,
    channel3_started: bool,
    channel3_wave_idx: usize,
    voice: Option<cpal::Voice>,
    blip: Option<BlipBuf>,
    bliptime: u32,
    blipval: i32,
    hz256: u32,
}

impl Sound {
    pub fn new() -> Sound {
        let voice = get_channel();
        if voice.is_none() {
            println!("Could not open audio device");
        }

        let blipbuf = voice.as_ref()
            .map(|v| {
                let mut bb = BlipBuf::new(v.format().samples_rate.0 / 10);
                bb.set_rates((1 << 22) as f64, v.format().samples_rate.0 as f64);
                bb
            });

        Sound {
            waveram: [0; 16],
            channel3_on: false,
            channel3_len: 0,
            channel3_vol: 0,
            channel3_freq: 0,
            channel3_uselen: false,
            channel3_started: false,
            channel3_freq_div: 0,
            channel3_wave_idx: 0,
            voice: voice,
            blip: blipbuf,
            bliptime: 0,
            blipval: 0,
            hz256: 0,
        }
    }

   pub fn rb(&self, a: u16) -> u8 {
        match a {
            0xFF1A => if self.channel3_on { 0x80 } else { 0 },
            0xFF1B => self.channel3_len,
            0xFF1C => self.channel3_vol << 5,
            0xFF1D => 0,
            0xFF1E => 0,
            0xFF30 ... 0xFF3F => self.waveram[a as usize - 0xFF30],
            _ => 0,
        }
    }

    pub fn wb(&mut self, a: u16, v: u8) {
        match a {
            0xFF1A => if v & 0x80 == 0x80 { self.channel3_on = true; } else { self.channel3_started = false; },
            0xFF1B => self.channel3_len = v,
            0xFF1C => self.channel3_vol = (v & 0x60) >> 5,
            0xFF1D => self.channel3_freq = self.channel3_freq & 0xFF00 | v as u32,
            0xFF1E => {
                self.channel3_freq = self.channel3_freq & 0x00FF | (((v & 0x7) as u32) << 8);
                self.channel3_started = v & 0x80 == 0x80;
                self.channel3_uselen = v & 0x40 == 0x40;
                self.channel3_wave_idx = 31;
                self.channel3_freq_div = 0;
                self.hz256 = 0;
            }
            0xFF30 ... 0xFF3F => self.waveram[a as usize - 0xFF30] = v,
            _ => (),
        }
    }

    #[inline]
    fn blip(&mut self) -> &mut BlipBuf {
        self.blip.as_mut().unwrap()
    }

    #[inline]
    fn channel(&mut self) -> &mut cpal::Voice {
        self.voice.as_mut().unwrap()
    }

    pub fn do_cycle(&mut self, cycles: u32)
    {
        self.bliptime += cycles;
        self.hz256 += cycles;
        let trigger256 = if self.hz256 >= (1 << 22) / 256 {
            self.hz256 -= (1 << 22) / 256;
            true
        }
        else {
            false
        };
        if self.channel3_started && self.channel3_on {
            //let rfreq = ((2048 - (self.channel3_freq as u32)) << 5);
            let rfreq = 64 * (2048 - (self.channel3_freq as u32));
            self.channel3_freq_div += cycles;
            if self.channel3_uselen && trigger256 {
                self.channel3_len = self.channel3_len.wrapping_sub(1);
                if self.channel3_len == 0 {
                    self.channel3_started = false;
                }
            }
            if self.channel3_freq_div > rfreq {
                self.channel3_freq_div -= rfreq;
                self.channel3_wave_idx = (self.channel3_wave_idx + 1) % 32;
                let sample = {
                    let ramitem = self.waveram[self.channel3_wave_idx / 2];
                    let shifted = if self.channel3_wave_idx % 2 == 0 {
                        ramitem >> 4
                    }
                    else {
                        ramitem & 0x0F
                    };
                    shifted as i8
                };
                let volmul = match self.channel3_vol {
                    1 => 1.0,
                    2 => 0.5,
                    3 => 0.25,
                    _ => 0.0,
                };
                let newblip = ((sample as f64 / 7.5 - 1.0) * volmul * 5000.0) as i32 - self.blipval;
                let time = self.bliptime;
                if self.blip.is_some() {
                    self.blip().add_delta(time, newblip);
                    self.blipval += newblip;
                }
            }
        }
        else if self.blipval != 0 && self.blip.is_some() {
            let time = self.bliptime;
            let newblip = -self.blipval;
            self.blip().add_delta(time, newblip);
            self.blipval = 0;
        }
        if self.bliptime >= (1 << 18) && self.blip.is_some() {
            self.blip().end_frame(1 << 18);
            self.bliptime -= 1 << 18;
            self.play_blipbuf();
        }
    }

    fn play_blipbuf(&mut self) {
        let channels_len = self.channel().format().channels.len();

        while self.blip().samples_avail() > 0 {
            let buf = &mut [0; 1 << 13];
            let count = self.blip().read_samples(buf, false);
            let blipbuf = &buf[..count];
            let mut done = 0;
            let mut lastdone = count;

            while lastdone != done && done < count {
                lastdone = done;
                let channelbuf = &blipbuf[done..];
                match self.channel().append_data(channelbuf.len()) {
                    cpal::UnknownTypeBuffer::U16(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            let value = *value as u16 + std::i16::MAX as u16;
                            for out in sample.iter_mut() { *out = value; }
                            done += 1;
                        }
                    }
                    cpal::UnknownTypeBuffer::I16(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            for out in sample.iter_mut() { *out = *value; }
                            done += 1;
                        }
                    }
                    cpal::UnknownTypeBuffer::F32(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            let value = *value as f32 / std::i16::MAX as f32;
                            for out in sample.iter_mut() { *out = value; }
                            done += 1;
                        }
                    }
                }
                self.channel().play();
            }
        }
    }
}

fn get_channel() -> Option<cpal::Voice> {
    if cpal::get_endpoints_list().count() == 0 { return None; }

    let endpoint = try_opt!(cpal::get_default_endpoint());
    let format = try_opt!(endpoint.get_supported_formats_list().ok().and_then(|mut v| v.next()));
    let channel = try_opt!(cpal::Voice::new(&endpoint, &format).ok());
    Some(channel)
}
<commit_msg>attempt at implementation of Channel 2<commit_after>use blip_buf::BlipBuf;
use cpal;
use std;

macro_rules! try_opt {
     ( $expr:expr ) => {
         match $expr {
             Some(v) => v,
             None => return None,
         }
     }
}

const WAVE_PATTERN : [[u8; 8]; 4] = [[0,0,0,0,1,0,0,0],[0,0,0,0,1,1,0,0],[0,0,1,1,1,1,0,0],[1,1,1,1,0,0,1,1]];

pub struct Sound {
    waveram: [u8; 32],
    channel2_started: bool,
    channel2_duty: u8,
    channel2_duty_cnt: u8,
    channel2_len: u8,
    channel2_freq: u32,
    channel2_freq_div: u32,
    channel2_uselen: bool,
    channel2_vol: u8,
    channel2_volup: bool,
    channel2_volsweep: u8,
    channel2_volcnt: u8,
    channel3_on: bool,
    channel3_len: u8,
    channel3_vol: u8,
    channel3_freq: u32,
    channel3_freq_div: u32,
    channel3_uselen: bool,
    channel3_started: bool,
    channel3_wave_idx: usize,
    voice: Option<cpal::Voice>,
    blip: Option<BlipBuf>,
    time: u32,
    blipval: i32,
    hz256: u32,
}

impl Sound {
    pub fn new() -> Sound {
        let voice = get_channel();
        if voice.is_none() {
            println!("Could not open audio device");
        }

        let blipbuf = voice.as_ref()
            .map(|v| {
                let mut bb = BlipBuf::new(v.format().samples_rate.0);
                bb.set_rates((1 << 22) as f64, v.format().samples_rate.0 as f64);
                println!("BB: {}", v.format().samples_rate.0);
                bb
            });

        Sound {
            waveram: [0; 32],
            channel2_started: false,
            channel2_duty: 0,
            channel2_duty_cnt: 0,
            channel2_len: 0,
            channel2_freq: 0,
            channel2_freq_div: 0,
            channel2_uselen: false,
            channel2_vol: 0,
            channel2_volup: false,
            channel2_volsweep: 0,
            channel2_volcnt: 0,
            channel3_on: false,
            channel3_len: 0,
            channel3_vol: 0,
            channel3_freq: 0,
            channel3_uselen: false,
            channel3_started: false,
            channel3_freq_div: 0,
            channel3_wave_idx: 0,
            voice: voice,
            blip: blipbuf,
            time: 0,
            blipval: 0,
            hz256: 0,
        }
    }

   pub fn rb(&self, a: u16) -> u8 {
        match a {
            0xFF1A => if self.channel3_on { 0x80 } else { 0 },
            0xFF1B => self.channel3_len,
            0xFF1C => self.channel3_vol << 5,
            0xFF1D => 0,
            0xFF1E => 0,
            0xFF30 ... 0xFF3F => {
                let wave_a = a as usize - 0xFF30;
                self.waveram[wave_a * 2] << 4 | self.waveram[wave_a * 2 + 1]
            },
            _ => 0,
        }
    }

    pub fn wb(&mut self, a: u16, v: u8) {
        match a {
            0xFF16 => {
                self.channel2_duty = (v & 0xC) >> 6;
                self.channel2_len = v & 0x3F;
            },
            0xFF17 => {
                self.channel2_volcnt = 0;
                self.channel2_vol = (v & 0xF0) >> 4;
                self.channel2_volup = v & 0x8 == 0x8;
                self.channel2_volsweep = v & 0x7;
            },
            0xFF18 => self.channel2_freq = self.channel3_freq & 0xFF00 | v as u32,
            0xFF19 => {
                self.channel2_freq = self.channel2_freq & 0x00FF | (((v & 0x7) as u32) << 8);
                self.channel2_started = v & 0x80 == 0x80;
                self.channel2_uselen = v & 0x40 == 0x40;
                self.channel2_freq_div = 0;
                self.channel2_duty_cnt = 7;
            },
            0xFF1A => if v & 0x80 == 0x80 { self.channel3_on = true; } else { self.channel3_started = false; },
            0xFF1B => self.channel3_len = v,
            0xFF1C => self.channel3_vol = (v & 0x60) >> 5,
            0xFF1D => self.channel3_freq = self.channel3_freq & 0xFF00 | v as u32,
            0xFF1E => {
                self.channel3_freq = self.channel3_freq & 0x00FF | (((v & 0x7) as u32) << 8);
                self.channel3_started = v & 0x80 == 0x80;
                self.channel3_uselen = v & 0x40 == 0x40;
                self.channel3_wave_idx = 31;
                self.channel3_freq_div = 0;
            }
            0xFF30 ... 0xFF3F => {
                let wave_a = a as usize - 0xFF30;
                self.waveram[wave_a * 2] = v >> 4;
                self.waveram[wave_a * 2 + 1] = v & 0xF;
            },
            _ => (),
        }
    }

    #[inline]
    fn blip(&mut self) -> &mut BlipBuf {
        self.blip.as_mut().unwrap()
    }

    #[inline]
    fn channel(&mut self) -> &mut cpal::Voice {
        self.voice.as_mut().unwrap()
    }

    pub fn do_cycle(&mut self, cycles: u32)
    {
        self.time += cycles;
        self.hz256 += cycles;

        let trigger256 = if self.hz256 >= (1 << 22) / 256 {
            self.hz256 -= (1 << 22) / 256;
            true
        }
        else {
            false
        };

        if self.channel2_started {
            let rfreq = 32 * (2048 - self.channel2_freq);
            self.channel2_freq_div += cycles;
            if self.channel2_uselen && trigger256 {
                if self.channel2_len == 0 {
                    self.channel2_len = 63;
                }
                else {
                    self.channel2_len -= 1;
                }
                if self.channel2_len == 0 {
                    self.channel2_started = false;
                }
            }

            if self.channel2_freq_div >= rfreq {
                self.channel2_freq_div -= rfreq;
                self.channel2_duty_cnt = (self.channel2_duty_cnt + 1) % 8;

                self.channel2_volcnt = (self.channel2_volcnt + 1) % 8;
                if self.channel2_volcnt == 0 && self.channel2_volsweep != 0 {
                    self.channel2_volsweep -= 1;
                    if self.channel2_volup && self.channel2_vol != 0xF {
                        self.channel2_vol += 1;
                    }
                    else if self.channel2_vol != 0 {
                        self.channel2_vol -= 1;
                    }
                }

                let sample = WAVE_PATTERN[self.channel2_duty as usize][self.channel2_duty_cnt as usize];

                if self.blip.is_some() {
                    let newblip = (sample as f64 * self.channel2_vol as f64 * (1.0/15.0) * 10000.0).round() as i32 - self.blipval;
                    let time = self.time;
                    self.blip().add_delta(time, newblip);
                    self.blipval += newblip;
                }
            }
        }

        /*
        if self.channel3_started && self.channel3_on {
            let rfreq = 32 * (2048 - (self.channel3_freq as u32));
            self.channel3_freq_div += cycles;
            if self.channel3_uselen && trigger256 {
                self.channel3_len = self.channel3_len.wrapping_sub(1);
                if self.channel3_len == 0 {
                    self.channel3_started = false;
                }
            }
            if self.channel3_freq_div >= rfreq {
                self.channel3_freq_div -= rfreq;
                self.channel3_wave_idx = (self.channel3_wave_idx + 1) % 32;
                let sample = self.waveram[self.channel3_wave_idx];
                let volmul = match self.channel3_vol {
                    1 => 1.0,
                    2 => 0.5,
                    3 => 0.25,
                    _ => 0.0,
                };
                let newblip = ((sample as f64 / 7.5 - 1.0) * volmul * 10000.0) as i32 - self.blipval;
                let time = self.time;
                if self.blip.is_some() {
                    self.blip().add_delta(time, newblip);
                    self.blipval += newblip;
                }
            }
        }*/
/*        else if self.blipval != 0 && self.blip.is_some() {
            let time = self.time;
            let newblip = -self.blipval;
            self.blip().add_delta(time, newblip);
            self.blipval = 0;
        }*/
        if self.time >= (1 << 17) && self.blip.is_some() {
            self.blip().end_frame(1 << 17);
            self.time -= 1 << 17;
            self.play_blipbuf();
        }
    }

    fn play_blipbuf(&mut self) {
        let channels_len = self.channel().format().channels.len();

        while self.blip().samples_avail() > 0 {
            let buf = &mut [0; 2048];
            let count = self.blip().read_samples(buf, false);
            let blipbuf = &buf[..count];
            let mut done = 0;
            let mut lastdone = count;

            while lastdone != done && done < count {
                lastdone = done;
                let channelbuf = &blipbuf[done..];
                match self.channel().append_data(channelbuf.len()) {
                    cpal::UnknownTypeBuffer::U16(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            let value = *value as u16 + std::i16::MAX as u16;
                            for out in sample.iter_mut() { *out = value; }
                            done += 1;
                        }
                    }
                    cpal::UnknownTypeBuffer::I16(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            for out in sample.iter_mut() { *out = *value; }
                            done += 1;
                        }
                    }
                    cpal::UnknownTypeBuffer::F32(mut buffer) => {
                        for (sample, value) in buffer.chunks_mut(channels_len).zip(channelbuf) {
                            let value = *value as f32 / std::i16::MAX as f32;
                            for out in sample.iter_mut() { *out = value; }
                            done += 1;
                        }
                    }
                }
                self.channel().play();
            }
        }
    }
}

fn get_channel() -> Option<cpal::Voice> {
    if cpal::get_endpoints_list().count() == 0 { return None; }

    let endpoint = try_opt!(cpal::get_default_endpoint());
    let format = try_opt!(endpoint.get_supported_formats_list().ok().and_then(|mut v| v.next()));

    cpal::Voice::new(&endpoint, &format).ok()
}
<|endoftext|>


<commit_before>use std::fmt;
use std::f64;
use std::f64::consts::PI;
use std::cmp::Ordering;

use radians::Radians;
use rand::{Rand, Rng};
use {Distance};

const MIN_SPEED: i32 = 1;
const MAX_SPEED: i32 = 25;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, Hash, Serialize, Deserialize)]
pub(crate) enum SpeedLevel {
    Value(i32),
    Instant,
}

impl PartialOrd for SpeedLevel {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        use self::SpeedLevel::*;
        match (*self, *other) {
            (Value(value), Value(ref other_value)) => value.partial_cmp(other_value),
            (Instant, Instant) => Some(Ordering::Equal),
            (Value(_), Instant) => Some(Ordering::Less),
            (Instant, Value(_)) => Some(Ordering::Greater),
        }
    }
}

/// Represents both the movement and rotation speed of the turtle.
///
/// # Creating Speeds
///
/// You can create a `Speed` value by converting either strings or numbers.
///
/// ```rust
/// # use turtle::Speed;
/// // This value is of type `Speed` and it is converted from an `i32`
/// let speed: Speed = 1.into();
///
/// // This value is of type `Speed` and it is converted from a `&str`
/// let slowest_speed: Speed = "slowest".into();
/// assert_eq!(speed, slowest_speed);
/// ```
///
/// There is no need to call `.into()` when passing a speed into the [`set_speed` method].
/// See the [`set_speed` method] for more information about how that works.
///
/// ```rust
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed(22); // Same as `turtle.set_speed(22.into())`
/// ```
///
/// **The minimum speed value is 1 and the maximum speed value (currently) is 25.**
///
/// Trying to set the speed to a value out of that range will cause a panic.
///
/// ```rust,should_panic
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed(26); // panic!
/// ```
///
/// While the minimum speed will not change, the maximum speed may grow larger if the need arises.
/// That is why we chose to panic for invalid speeds instead of defaulting to another value.
///
/// ### String Conversion
///
/// Strings are converted as follows:
///
/// | String      | Value |
/// | ----------- | ----- |
/// | `"slowest"` | `1`   |
/// | `"slower"`  | `5`   |
/// | `"slow"`    | `8`   |
/// | `"normal"`  | `10`  |
/// | `"fast"`    | `12`  |
/// | `"faster"`  | `15`  |
/// | `"instant"` | [see below](#instant) |
///
/// You can use strings to create `Speed` values in the same way numbers were used above. All
/// three of the following are equivalent:
///
/// ```rust
/// # use turtle::{Turtle, Speed};
/// # let mut turtle = Turtle::new();
/// turtle.set_speed(5);
/// turtle.set_speed("slower");
/// turtle.set_speed(Speed::from("slower")); // Not recommended!
/// ```
///
/// # Instant
///
/// There is one special speed value `"instant"` which makes it so that movement and rotation
/// are not animated at all. Instead, the turtle immediately moves and rotates to the position that
/// you directed it to. It will still draw along the way if its pen is down.
///
/// ```rust
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed("instant");
/// turtle.forward(100.0); // A line will be drawn instantly!
/// ```
///
/// # Comparing Speed Values
///
/// `Speed` values can be compared for equality with `i32` values. This is a little more convenient
/// than converting the `i32` to `Speed` every time you want to make a comparison.
///
/// ```rust
/// # use turtle::Speed;
/// let speed: Speed = 1.into();
/// // Speed values can be compared to integers
/// assert_eq!(speed, 1);
/// // This is equivalent to the following
/// assert_eq!(speed, Speed::from(1));
///
/// // This value is of type `Speed` and it is converted from a `&str`
/// let speed: Speed = "slowest".into();
/// // Speed values can be compared to integers
/// assert_eq!(speed, 1);
/// // This is equivalent to the following
/// assert_eq!(speed, Speed::from("slowest"));
/// ```
///
/// You can use the `<`, `<=`, `==`, `>=`, `>` with `Speed` values and `i32` values or other
/// `Speed` values.
///
/// ```rust,no_run
/// # use turtle::{Turtle, Speed};
/// let turtle = Turtle::new();
/// let speed = turtle.speed();
/// if speed == 12 && speed >= 5 && speed < Speed::instant() {
///     println!("Super fast!!");
/// }
/// // This is equivalent, but requires more typing
/// if speed == Speed::from(12) && speed >= Speed::from(5) && speed < Speed::from("instant") {
///     println!("Super fast!!");
/// }
/// ```
///
/// Notice that you can compare `Speed` values to numeric values, but not the other way around.
///
/// ```rust,compile_fail
/// # use turtle::Speed;
/// let speed: Speed = 7.into();
/// if 8 > speed { // This doesn't make sense and won't compile!
///     // ...
/// }
/// ```
///
/// To check if a speed is instant, use the [`is_instant()` method] or compare the speed to
/// [`Speed::instant()`].
///
/// ```rust
/// # use turtle::Speed;
/// let speed = Speed::instant();
/// if speed.is_instant() {
///     println!("Instant!!");
/// }
/// # else { panic!("Speed::instant() was not instant!"); }
/// ```
///
/// [`set_speed` method]: struct.Turtle.html#method.set_speed
/// [`Speed::instant()`]: struct.Speed.html#method.instant
/// [`is_instant()` method]: struct.Speed.html#method.is_instant
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Speed(SpeedLevel);

impl Speed {
    /// Returns the speed value that will make the turtle move and rotate instantly. This means
    /// that instead of the turtle's movements being animated, it will directly move to wherever
    /// you direct it to go.
    ///
    /// ```rust
    /// # use turtle::{Turtle, Speed};
    /// let mut turtle = Turtle::new();
    /// turtle.set_speed(Speed::instant());
    /// turtle.forward(100.0); // A line will be drawn instantly!
    /// ```
    ///
    /// Whenever possible, you should prefer to use the string `"instant"` instead of calling this
    /// method.
    ///
    /// ```rust
    /// # use turtle::{Turtle};
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("instant"); // equivalent to typing `Speed::instant()`
    /// ```
    pub fn instant() -> Self {
        Speed(SpeedLevel::Instant)
    }

    /// Returns true if this speed is the same as `Speed::instant()`
    ///
    /// ```rust
    /// use turtle::{Speed};
    /// let speed: Speed = "instant".into();
    /// assert!(speed.is_instant());
    ///
    /// let speed = Speed::instant();
    /// assert!(speed.is_instant());
    /// ```
    pub fn is_instant(self) -> bool {
        match self {
            Speed(SpeedLevel::Instant) => true,
            _ => false,
        }
    }

    /// Converts a speed to its value as a movement speed in pixels per second
    pub(crate) fn to_movement(self) -> Distance {
        use self::SpeedLevel::*;
        match self.0 {
            Value(speed) => speed as f64 * 50.0,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub(crate) fn to_rotation(self) -> Radians {
        use self::SpeedLevel::*;
        Radians::from_radians_value(match self.0 {
            Value(speed) => speed as f64 * (3.0*PI),
            Instant => f64::INFINITY,
        })
    }
}

impl fmt::Display for Speed {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SpeedLevel::*;
        match self.0 {
            Value(speed) => write!(f, "Speed::from({})", speed),
            Instant => write!(f, "Speed::instant()"),
        }
    }
}

impl PartialEq<i32> for Speed {
    fn eq(&self, other: &i32) -> bool {
        self.eq(&Speed::from(*other))
    }
}

impl PartialOrd<i32> for Speed {
    fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
        return self.partial_cmp(&Speed::from(*other));
    }
}

impl Rand for Speed {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        rng.gen_range(MIN_SPEED, MAX_SPEED + 1).into()
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use self::SpeedLevel::*;

        Speed(match s {
            "slowest" => Value(1),
            "slower" => Value(5),
            "slow" => Value(8),
            "normal" => Value(10),
            "fast" => Value(12),
            "faster" => Value(15),
            "instant" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slower', 'slow', 'normal', 'fast', 'faster', 'instant'"),
        })
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use self::SpeedLevel::*;

        Speed(match n {
            // Special error message for 0 because this used to be a valid speed
            0 => panic!("Invalid speed: 0. If you wanted to set the speed to instant, please use the string \"instant\" or Speed::instant()"),
            n if n >= MIN_SPEED && n <= MAX_SPEED => Value(n),
            n => panic!("Invalid speed: {}. Must be a value between 1 and {}", n, MAX_SPEED),
        })
    }
}

// We include this implementation because we use f64 in the rest of the library.
// It makes sense to implement this so that they don't get messed up if they accidentally use a
// floating point literal with set_speed.
impl From<f64> for Speed {
    fn from(n: f64) -> Self {
        (n.round() as i32).into()
    }
}

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

    #[test]
    fn display() {
        let speed: Speed = "instant".into();
        assert_eq!(format!("{}", speed), "Speed::instant()");
        for value in 1..MAX_SPEED {
            let speed: Speed = value.into();
            assert_eq!(format!("{}", speed), format!("Speed::from({})", value));
        }
    }

    #[test]
    fn speed_strings() {
        let mut turtle = Turtle::new();
        turtle.set_speed("slowest");
        assert_eq!(turtle.speed(), 1);
        turtle.set_speed("slower");
        assert_eq!(turtle.speed(), 5);
        turtle.set_speed("slow");
        assert_eq!(turtle.speed(), 8);
        turtle.set_speed("normal");
        assert_eq!(turtle.speed(), 10);
        turtle.set_speed("fast");
        assert_eq!(turtle.speed(), 12);
        turtle.set_speed("faster");
        assert_eq!(turtle.speed(), 15);
        turtle.set_speed("instant");
        assert_eq!(turtle.speed(), Speed::instant());
    }

    #[test]
    #[should_panic(expected = "Invalid speed specified, use one of the words: 'slowest', 'slower', 'slow', 'normal', 'fast', 'faster', 'instant'")]
    fn invalid_speed() {
        let mut turtle = Turtle::new();
        turtle.set_speed("wrong");
    }

    #[test]
    fn speed_values() {
        let mut turtle = Turtle::new();
        for speed in 1..MAX_SPEED {
            turtle.set_speed(speed);
            assert_eq!(turtle.speed(), speed);
        }
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 26. Must be a value between 1 and 25")]
    fn speed_value_out_of_range() {
        let mut turtle = Turtle::new();
        turtle.set_speed(26);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 20394. Must be a value between 1 and 25")]
    fn speed_value_out_of_range2() {
        let mut turtle = Turtle::new();
        turtle.set_speed(20394);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: -1. Must be a value between 1 and 25")]
    fn speed_value_out_of_range_negative() {
        let mut turtle = Turtle::new();
        turtle.set_speed(-1);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 0. If you wanted to set the speed to instant, please use the string \"instant\" or Speed::instant()")]
    fn disallow_zero() {
        let mut turtle = Turtle::new();
        turtle.set_speed(0);
    }

    #[test]
    fn speed_values_f64() {
        let mut turtle = Turtle::new();
        for speed in 1..MAX_SPEED {
            turtle.set_speed(speed as f64 + 0.4);
            assert_eq!(turtle.speed(), speed);
        }
    }
}
<commit_msg>Fixes for some tests and error messages<commit_after>use std::fmt;
use std::f64;
use std::f64::consts::PI;
use std::cmp::Ordering;

use radians::Radians;
use rand::{Rand, Rng};
use {Distance};

const MIN_SPEED: i32 = 1;
const MAX_SPEED: i32 = 25;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, Hash, Serialize, Deserialize)]
pub(crate) enum SpeedLevel {
    Value(i32),
    Instant,
}

impl PartialOrd for SpeedLevel {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        use self::SpeedLevel::*;
        match (*self, *other) {
            (Value(value), Value(ref other_value)) => value.partial_cmp(other_value),
            (Instant, Instant) => Some(Ordering::Equal),
            (Value(_), Instant) => Some(Ordering::Less),
            (Instant, Value(_)) => Some(Ordering::Greater),
        }
    }
}

/// Represents both the movement and rotation speed of the turtle.
///
/// # Creating Speeds
///
/// You can create a `Speed` value by converting either strings or numbers.
///
/// ```rust
/// # use turtle::Speed;
/// // This value is of type `Speed` and it is converted from an `i32`
/// let speed: Speed = 1.into();
///
/// // This value is of type `Speed` and it is converted from a `&str`
/// let slowest_speed: Speed = "slowest".into();
/// assert_eq!(speed, slowest_speed);
/// ```
///
/// There is no need to call `.into()` when passing a speed into the [`set_speed` method].
/// See the [`set_speed` method] for more information about how that works.
///
/// ```rust
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed(22); // Same as `turtle.set_speed(22.into())`
/// ```
///
/// **The minimum speed value is 1 and the maximum speed value (currently) is 25.**
///
/// Trying to set the speed to a value out of that range will cause a panic.
///
/// ```rust,should_panic
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed(26); // panic!
/// ```
///
/// While the minimum speed will not change, the maximum speed may grow larger if the need arises.
/// That is why we chose to panic for invalid speeds instead of defaulting to another value.
///
/// ### String Conversion
///
/// Strings are converted as follows:
///
/// | String      | Value |
/// | ----------- | ----- |
/// | `"slowest"` | `1`   |
/// | `"slower"`  | `5`   |
/// | `"slow"`    | `8`   |
/// | `"normal"`  | `10`  |
/// | `"fast"`    | `12`  |
/// | `"faster"`  | `15`  |
/// | `"instant"` | [see below](#instant) |
///
/// You can use strings to create `Speed` values in the same way numbers were used above. All
/// three of the following are equivalent:
///
/// ```rust
/// # use turtle::{Turtle, Speed};
/// # let mut turtle = Turtle::new();
/// turtle.set_speed(5);
/// turtle.set_speed("slower");
/// turtle.set_speed(Speed::from("slower")); // Not recommended!
/// ```
///
/// # Instant
///
/// There is one special speed value `"instant"` which makes it so that movement and rotation
/// are not animated at all. Instead, the turtle immediately moves and rotates to the position that
/// you directed it to. It will still draw along the way if its pen is down.
///
/// ```rust
/// # use turtle::{Turtle};
/// let mut turtle = Turtle::new();
/// turtle.set_speed("instant");
/// turtle.forward(100.0); // A line will be drawn instantly!
/// ```
///
/// # Comparing Speed Values
///
/// `Speed` values can be compared for equality with `i32` values. This is a little more convenient
/// than converting the `i32` to `Speed` every time you want to make a comparison.
///
/// ```rust
/// # use turtle::Speed;
/// let speed: Speed = 1.into();
/// // Speed values can be compared to integers
/// assert_eq!(speed, 1);
/// // This is equivalent to the following
/// assert_eq!(speed, Speed::from(1));
///
/// // This value is of type `Speed` and it is converted from a `&str`
/// let speed: Speed = "slowest".into();
/// // Speed values can be compared to integers
/// assert_eq!(speed, 1);
/// // This is equivalent to the following
/// assert_eq!(speed, Speed::from("slowest"));
/// ```
///
/// You can use the `<`, `<=`, `==`, `>=`, `>` with `Speed` values and `i32` values or other
/// `Speed` values.
///
/// ```rust,no_run
/// # use turtle::{Turtle, Speed};
/// let turtle = Turtle::new();
/// let speed = turtle.speed();
/// if speed == 12 && speed >= 5 && speed < Speed::instant() {
///     println!("Super fast!!");
/// }
/// // This is equivalent, but requires more typing
/// if speed == Speed::from(12) && speed >= Speed::from(5) && speed < Speed::from("instant") {
///     println!("Super fast!!");
/// }
/// ```
///
/// Notice that you can compare `Speed` values to numeric values, but not the other way around.
///
/// ```rust,compile_fail
/// # use turtle::Speed;
/// let speed: Speed = 7.into();
/// if 8 > speed { // This doesn't make sense and won't compile!
///     // ...
/// }
/// ```
///
/// To check if a speed is instant, use the [`is_instant()` method] or compare the speed to
/// [`Speed::instant()`].
///
/// ```rust
/// # use turtle::Speed;
/// let speed = Speed::instant();
/// if speed.is_instant() {
///     println!("Instant!!");
/// }
/// # else { panic!("Speed::instant() was not instant!"); }
/// ```
///
/// [`set_speed` method]: struct.Turtle.html#method.set_speed
/// [`Speed::instant()`]: struct.Speed.html#method.instant
/// [`is_instant()` method]: struct.Speed.html#method.is_instant
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Speed(SpeedLevel);

impl Speed {
    /// Returns the speed value that will make the turtle move and rotate instantly. This means
    /// that instead of the turtle's movements being animated, it will directly move to wherever
    /// you direct it to go.
    ///
    /// ```rust
    /// # use turtle::{Turtle, Speed};
    /// let mut turtle = Turtle::new();
    /// turtle.set_speed(Speed::instant());
    /// turtle.forward(100.0); // A line will be drawn instantly!
    /// ```
    ///
    /// Whenever possible, you should prefer to use the string `"instant"` instead of calling this
    /// method.
    ///
    /// ```rust
    /// # use turtle::{Turtle};
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("instant"); // equivalent to typing `Speed::instant()`
    /// ```
    pub fn instant() -> Self {
        Speed(SpeedLevel::Instant)
    }

    /// Returns true if this speed is the same as `Speed::instant()`
    ///
    /// ```rust
    /// use turtle::{Speed};
    /// let speed: Speed = "instant".into();
    /// assert!(speed.is_instant());
    ///
    /// let speed = Speed::instant();
    /// assert!(speed.is_instant());
    /// ```
    pub fn is_instant(self) -> bool {
        match self {
            Speed(SpeedLevel::Instant) => true,
            _ => false,
        }
    }

    /// Converts a speed to its value as a movement speed in pixels per second
    pub(crate) fn to_movement(self) -> Distance {
        use self::SpeedLevel::*;
        match self.0 {
            Value(speed) => speed as f64 * 50.0,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub(crate) fn to_rotation(self) -> Radians {
        use self::SpeedLevel::*;
        Radians::from_radians_value(match self.0 {
            Value(speed) => speed as f64 * (3.0*PI),
            Instant => f64::INFINITY,
        })
    }
}

impl fmt::Display for Speed {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SpeedLevel::*;
        match self.0 {
            Value(speed) => write!(f, "Speed::from({})", speed),
            Instant => write!(f, "Speed::instant()"),
        }
    }
}

impl PartialEq<i32> for Speed {
    fn eq(&self, other: &i32) -> bool {
        self.eq(&Speed::from(*other))
    }
}

impl PartialOrd<i32> for Speed {
    fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
        return self.partial_cmp(&Speed::from(*other));
    }
}

impl Rand for Speed {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        rng.gen_range(MIN_SPEED, MAX_SPEED + 1).into()
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use self::SpeedLevel::*;

        Speed(match s {
            "slowest" => Value(1),
            "slower" => Value(5),
            "slow" => Value(8),
            "normal" => Value(10),
            "fast" => Value(12),
            "faster" => Value(15),
            "instant" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: \"slowest\", \"slower\", \"slow\", \"normal\", \"fast\", \"faster\", \"instant\""),
        })
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use self::SpeedLevel::*;

        Speed(match n {
            // Special error message for 0 because this used to be a valid speed
            0 => panic!("Invalid speed: 0. If you wanted to set the speed to instant, please use the string \"instant\" or Speed::instant()"),
            n if n >= MIN_SPEED && n <= MAX_SPEED => Value(n),
            n => panic!("Invalid speed: {}. Must be a value between {} and {}", n, MIN_SPEED, MAX_SPEED),
        })
    }
}

// We include this implementation because we use f64 in the rest of the library.
// It makes sense to implement this so that they don't get messed up if they accidentally use a
// floating point literal with set_speed.
impl From<f64> for Speed {
    fn from(n: f64) -> Self {
        (n.round() as i32).into()
    }
}

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

    #[test]
    fn display() {
        let speed: Speed = "instant".into();
        assert_eq!(format!("{}", speed), "Speed::instant()");
        for value in 1..MAX_SPEED {
            let speed: Speed = value.into();
            assert_eq!(format!("{}", speed), format!("Speed::from({})", value));
        }
    }

    #[test]
    fn speed_strings() {
        let mut turtle = Turtle::new();
        turtle.set_speed("slowest");
        assert_eq!(turtle.speed(), 1);
        turtle.set_speed("slower");
        assert_eq!(turtle.speed(), 5);
        turtle.set_speed("slow");
        assert_eq!(turtle.speed(), 8);
        turtle.set_speed("normal");
        assert_eq!(turtle.speed(), 10);
        turtle.set_speed("fast");
        assert_eq!(turtle.speed(), 12);
        turtle.set_speed("faster");
        assert_eq!(turtle.speed(), 15);
        turtle.set_speed("instant");
        assert_eq!(turtle.speed(), Speed::instant());
    }

    #[test]
    #[should_panic(expected = "Invalid speed specified, use one of the words: \"slowest\", \"slower\", \"slow\", \"normal\", \"fast\", \"faster\", \"instant\"")]
    fn invalid_speed() {
        let mut turtle = Turtle::new();
        turtle.set_speed("wrong");
    }

    #[test]
    fn speed_values() {
        let mut turtle = Turtle::new();
        for speed in 1..(MAX_SPEED + 1) {
            turtle.set_speed(speed);
            assert_eq!(turtle.speed(), speed);
        }
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 26. Must be a value between 1 and 25")]
    fn speed_value_out_of_range() {
        let mut turtle = Turtle::new();
        turtle.set_speed(26);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 20394. Must be a value between 1 and 25")]
    fn speed_value_out_of_range2() {
        let mut turtle = Turtle::new();
        turtle.set_speed(20394);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: -1. Must be a value between 1 and 25")]
    fn speed_value_out_of_range_negative() {
        let mut turtle = Turtle::new();
        turtle.set_speed(-1);
    }

    #[test]
    #[should_panic(expected = "Invalid speed: 0. If you wanted to set the speed to instant, please use the string \"instant\" or Speed::instant()")]
    fn disallow_zero() {
        let mut turtle = Turtle::new();
        turtle.set_speed(0);
    }

    #[test]
    fn speed_values_f64() {
        let mut turtle = Turtle::new();
        for speed in 1..MAX_SPEED {
            turtle.set_speed(speed as f64 + 0.4);
            assert_eq!(turtle.speed(), speed);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_atomic;
extern crate slog_json;
extern crate slog_stream;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use nix::sys::signal;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;

use std::{thread, io};
use slog::*;
use slog_atomic::*;
use slog_stream::*;

lazy_static! {
    // global atomic switch drain control
    static ref ATOMIC_DRAIN_SWITCH : AtomicSwitchCtrl<io::Error> = AtomicSwitch::new(
        Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should no happen"))
    ).ctrl();

    // track current state of the atomic switch drain
    static ref ATOMIC_DRAIN_SWITCH_STATE : AtomicBool = AtomicBool::new(false);
}

fn atomic_drain_switch() {
    // XXX: Not atomic. Race?
    let new = !ATOMIC_DRAIN_SWITCH_STATE.load(SeqCst);
    ATOMIC_DRAIN_SWITCH_STATE.store(new, SeqCst);

    if new {
        ATOMIC_DRAIN_SWITCH.set(stream(io::stdout(), slog_json::default()))
    } else {
        ATOMIC_DRAIN_SWITCH.set(slog_term::streamer().full().stdout().build())
    }
}

extern "C" fn handle_sigusr1(_: i32) {
    atomic_drain_switch();
}

fn main() {
    unsafe {
        let sig_action = signal::SigAction::new(signal::SigHandler::Handler(handle_sigusr1),
                                                signal::SaFlags::empty(),
                                                signal::SigSet::empty());
        signal::sigaction(signal::SIGUSR1, &sig_action).unwrap();
    }

    let drain = slog::duplicate(slog_term::streamer().stderr().full().build(), ATOMIC_DRAIN_SWITCH.drain()).fuse();

    atomic_drain_switch();

    let log = Logger::root(drain, o!());

    info!(log, "logging a message every 3s");
    info!(log, "send SIGUSR1 signal to switch output with");
    let pid = nix::unistd::getpid();
    info!(log, "kill -SIGUSR1 {}", pid);
    loop {
        info!(log, "tick");
        thread::sleep_ms(3000);
    }
}
<commit_msg>chore(example): update signal example to use `thread::sleep`<commit_after>#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_atomic;
extern crate slog_json;
extern crate slog_stream;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use nix::sys::signal;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::time::Duration;

use std::{thread, io};
use slog::*;
use slog_atomic::*;
use slog_stream::*;

lazy_static! {
    // global atomic switch drain control
    static ref ATOMIC_DRAIN_SWITCH : AtomicSwitchCtrl<io::Error> = AtomicSwitch::new(
        Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should no happen"))
    ).ctrl();

    // track current state of the atomic switch drain
    static ref ATOMIC_DRAIN_SWITCH_STATE : AtomicBool = AtomicBool::new(false);
}

fn atomic_drain_switch() {
    // XXX: Not atomic. Race?
    let new = !ATOMIC_DRAIN_SWITCH_STATE.load(SeqCst);
    ATOMIC_DRAIN_SWITCH_STATE.store(new, SeqCst);

    if new {
        ATOMIC_DRAIN_SWITCH.set(stream(io::stdout(), slog_json::default()))
    } else {
        ATOMIC_DRAIN_SWITCH.set(slog_term::streamer().full().stdout().build())
    }
}

extern "C" fn handle_sigusr1(_: i32) {
    atomic_drain_switch();
}

fn main() {
    unsafe {
        let sig_action = signal::SigAction::new(signal::SigHandler::Handler(handle_sigusr1),
                                                signal::SaFlags::empty(),
                                                signal::SigSet::empty());
        signal::sigaction(signal::SIGUSR1, &sig_action).unwrap();
    }

    let drain = slog::duplicate(slog_term::streamer().stderr().full().build(), ATOMIC_DRAIN_SWITCH.drain()).fuse();

    atomic_drain_switch();

    let log = Logger::root(drain, o!());

    info!(log, "logging a message every 3s");
    info!(log, "send SIGUSR1 signal to switch output with");
    let pid = nix::unistd::getpid();
    info!(log, "kill -SIGUSR1 {}", pid);
    loop {
        info!(log, "tick");
        thread::sleep(Duration::from_millis(3000));
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::rc::Rc;
use std::cell::RefCell;

use std::fs::File;
use std::io::{BufRead, BufReader};

use timely::*;
use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::drain::DrainExt;

use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::channels::pact::Pipeline;

use differential_dataflow::Collection;
use differential_dataflow::operators::group::GroupBy;
use differential_dataflow::operators::join::JoinBy;

fn main() {

    let parts_pattern = std::env::args().nth(2).unwrap();
    let items_pattern = std::env::args().nth(3).unwrap();
    let delimiter = std::env::args().nth(4).unwrap();

    timely::execute_from_args(std::env::args().skip(4), move |computation| {

        let comm_index = computation.index();
        let comm_peers = computation.peers();

        let mut start = time::precise_time_s();

        let epoch = Rc::new(RefCell::new(0u64));
        let clone = epoch.clone();

        // form the TPCH17-like query
        let (mut parts, mut items) = computation.scoped(|builder| {

            let (part_input, parts) = builder.new_input::<((u32, String, String), i32)>();
            let (item_input, items) = builder.new_input::<((u32, u32, u64), i32)>();

            let parts = Collection::new(parts);
            let items = Collection::new(items);

            // filter parts by brand and container
            let parts = parts.filter(|x| x.1 == "Brand#23" && x.2 == "MED BOX")
                             .map(|(key, _, _)| key);

            // restrict lineitems to those of the relevant part
            let items = items.join_by_u(&parts, |x| (x.0, (x.1,x.2)), |y| (y,()), |k,x,_| (*k,x.0,x.1));

            // compute the average quantities
            let average = items.group_by_u(|(x,y,_)| (x,y), |k,v| (*k,*v), |_,s,t| {
                let mut sum = 0;
                let mut cnt = 0;
                for (&val,wgt) in s {
                    cnt += wgt;
                    sum += val;
                }
                t.push((sum / cnt as u32, 1));
            });

            // join items against their averages, filter by quantity, remove filter coordinate
            items.join_by_u(&average, |x| (x.0, (x.1, x.2)), |y| y, |k, x, f| (*k, x.0, x.1, *f))
                 .filter(|&(_, q, _, avg)| q < avg / 5)
                 .map(|(key, _, price, _)| (key, price))
                 .inner
                 .unary_notify::<u32, _, _>(Pipeline, "Subscribe", vec![RootTimestamp::new(0)], move |i,_,n| {
                     while let Some(_) = i.next() { }
                     for (time,_) in n.next() {
                         *clone.borrow_mut() = time.inner + 1;
                         if n.frontier(0).len() > 0 {
                             n.notify_at(&RootTimestamp::new(*clone.borrow()));
                         }
                     }
                 })
                 ;

            (part_input, item_input)
        });

        // read the parts input file
        if let Ok(parts_file) = File::open(format!("{}-{}-{}", parts_pattern, comm_index, comm_peers)) {
            let parts_reader = BufReader::new(parts_file);
            for (index, line) in parts_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    let part_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let brand = fields.next().unwrap().to_owned();
                    fields.next();
                    fields.next();
                    let container = fields.next().unwrap().to_owned();
                    parts.send(((part_id, brand, container), 1));
                }
            }

            computation.step();
        }
        else { println!("worker {}: did not find input {}-{}-{}", computation.index(), parts_pattern, comm_index, comm_peers); }

        // read the lineitems input file
        let mut items_buffer = Vec::new();
        if let Ok(items_file) = File::open(format!("{}-{}-{}", items_pattern, comm_index, comm_peers)) {
            let items_reader =  BufReader::new(items_file);
            for (index, line) in items_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    fields.next();
                    let item_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let quantity = fields.next().unwrap().parse::<u32>().unwrap();
                    let extended_price = fields.next().unwrap().parse::<f64>().unwrap() as u64;
                    items_buffer.push(((item_id, quantity, extended_price), 1i32));
                }
            }
        }
        else { println!("worker {}: did not find input {}-{}-{}", comm_index, items_pattern, comm_index, comm_peers); }

        println!("data loaded at {}", time::precise_time_s() - start);
        start = time::precise_time_s();

        parts.close();
        let item_count = items_buffer.len();

        for (index, item) in items_buffer.drain_temp().enumerate() {
            items.send(item);
            items.advance_to(index as u64 + 1);
            while *epoch.borrow() <= index as u64 {
                computation.step();
            }
        }

        // items.send_at(0, items_buffer.drain_temp());

        items.close();

        while computation.step() { }
        computation.step(); // shut down

        println!("computation finished at {}", time::precise_time_s() - start);
        println!("rate: {}", (item_count as f64) / (time::precise_time_s() - start));
    });
}
<commit_msg>remove reliance on timely::DrainExt<commit_after>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::rc::Rc;
use std::cell::RefCell;

use std::fs::File;
use std::io::{BufRead, BufReader};

use timely::*;
use timely::dataflow::*;
use timely::dataflow::operators::*;

use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::channels::pact::Pipeline;

use differential_dataflow::Collection;
use differential_dataflow::operators::group::GroupBy;
use differential_dataflow::operators::join::JoinBy;

fn main() {

    let parts_pattern = std::env::args().nth(2).unwrap();
    let items_pattern = std::env::args().nth(3).unwrap();
    let delimiter = std::env::args().nth(4).unwrap();

    timely::execute_from_args(std::env::args().skip(4), move |computation| {

        let comm_index = computation.index();
        let comm_peers = computation.peers();

        let mut start = time::precise_time_s();

        let epoch = Rc::new(RefCell::new(0u64));
        let clone = epoch.clone();

        // form the TPCH17-like query
        let (mut parts, mut items) = computation.scoped(|builder| {

            let (part_input, parts) = builder.new_input::<((u32, String, String), i32)>();
            let (item_input, items) = builder.new_input::<((u32, u32, u64), i32)>();

            let parts = Collection::new(parts);
            let items = Collection::new(items);

            // filter parts by brand and container
            let parts = parts.filter(|x| x.1 == "Brand#23" && x.2 == "MED BOX")
                             .map(|(key, _, _)| key);

            // restrict lineitems to those of the relevant part
            let items = items.join_by_u(&parts, |x| (x.0, (x.1,x.2)), |y| (y,()), |k,x,_| (*k,x.0,x.1));

            // compute the average quantities
            let average = items.group_by_u(|(x,y,_)| (x,y), |k,v| (*k,*v), |_,s,t| {
                let mut sum = 0;
                let mut cnt = 0;
                for (&val,wgt) in s {
                    cnt += wgt;
                    sum += val;
                }
                t.push((sum / cnt as u32, 1));
            });

            // join items against their averages, filter by quantity, remove filter coordinate
            items.join_by_u(&average, |x| (x.0, (x.1, x.2)), |y| y, |k, x, f| (*k, x.0, x.1, *f))
                 .filter(|&(_, q, _, avg)| q < avg / 5)
                 .map(|(key, _, price, _)| (key, price))
                 .inner
                 .unary_notify::<u32, _, _>(Pipeline, "Subscribe", vec![RootTimestamp::new(0)], move |i,_,n| {
                     while let Some(_) = i.next() { }
                     for (time,_) in n.next() {
                         *clone.borrow_mut() = time.inner + 1;
                         if n.frontier(0).len() > 0 {
                             n.notify_at(&RootTimestamp::new(*clone.borrow()));
                         }
                     }
                 })
                 ;

            (part_input, item_input)
        });

        // read the parts input file
        if let Ok(parts_file) = File::open(format!("{}-{}-{}", parts_pattern, comm_index, comm_peers)) {
            let parts_reader = BufReader::new(parts_file);
            for (index, line) in parts_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    let part_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let brand = fields.next().unwrap().to_owned();
                    fields.next();
                    fields.next();
                    let container = fields.next().unwrap().to_owned();
                    parts.send(((part_id, brand, container), 1));
                }
            }

            computation.step();
        }
        else { println!("worker {}: did not find input {}-{}-{}", computation.index(), parts_pattern, comm_index, comm_peers); }

        // read the lineitems input file
        let mut items_buffer = Vec::new();
        if let Ok(items_file) = File::open(format!("{}-{}-{}", items_pattern, comm_index, comm_peers)) {
            let items_reader =  BufReader::new(items_file);
            for (index, line) in items_reader.lines().enumerate() {
                if index % comm_peers == comm_index {
                    let text = line.ok().expect("read error");
                    let mut fields = text.split(&delimiter);
                    fields.next();
                    let item_id = fields.next().unwrap().parse::<u32>().unwrap();
                    fields.next();
                    fields.next();
                    let quantity = fields.next().unwrap().parse::<u32>().unwrap();
                    let extended_price = fields.next().unwrap().parse::<f64>().unwrap() as u64;
                    items_buffer.push(((item_id, quantity, extended_price), 1i32));
                }
            }
        }
        else { println!("worker {}: did not find input {}-{}-{}", comm_index, items_pattern, comm_index, comm_peers); }

        println!("data loaded at {}", time::precise_time_s() - start);
        start = time::precise_time_s();

        parts.close();
        let item_count = items_buffer.len();

        for (index, item) in items_buffer.drain(..).enumerate() {
            items.send(item);
            items.advance_to(index as u64 + 1);
            while *epoch.borrow() <= index as u64 {
                computation.step();
            }
        }

        // items.send_at(0, items_buffer.drain_temp());

        items.close();

        while computation.step() { }
        computation.step(); // shut down

        println!("computation finished at {}", time::precise_time_s() - start);
        println!("rate: {}", (item_count as f64) / (time::precise_time_s() - start));
    });
}
<|endoftext|>


<commit_before>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for Bash
///
/// The `kernel-bash.sh` script relies on `/dev/stdin`, `/dev/stdout`,
/// and `/dev/stderr` so this kernel is not available on Windows.
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "bash-micro",
        &["Bash", "Shell"],
        true,
        false,
        false,
        ("bash", "*"),
        &["{{script}}"],
        include_file!("bash-kernel.sh"),
        &[],
        "{{name}}={{json}}",
        "echo ${{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        common::{
            eyre::{bail, Result},
            tokio,
        },
        stencila_schema::Node,
        KernelTrait,
    };
    use test_utils::{assert_json_eq, common::serde_json::json, skip_ci_os};

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        if skip_ci_os("windows", "test currently failing on windows") {
            return Ok(());
        }

        let mut kernel = new();
        match kernel.is_available().await {
            true => kernel.start_here().await?,
            false => return Ok(()),
        }

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a=2\necho $a", None).await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [2]);

        // Syntax error
        let (outputs, messages) = kernel.exec("if", None).await?;
        assert!(messages[0]
            .error_message
            .ends_with("syntax error: unexpected end of file"));
        assert_json_eq!(outputs, json!([]));

        // Runtime error
        let (outputs, messages) = kernel.exec("foo", None).await?;
        assert!(messages[0]
            .error_message
            .ends_with("foo: command not found"));
        assert_json_eq!(outputs, json!([]));

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_eq!(b, 3);

        // Use both variables
        let (outputs, messages) = kernel.exec("echo $a$b", None).await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [23]);

        Ok(())
    }

    #[tokio::test]
    async fn percent_escaping() -> Result<()> {
        if skip_ci_os("windows", "test currently failing on windows") {
            return Ok(());
        }

        let mut kernel = new();
        match kernel.is_available().await {
            true => kernel.start_here().await?,
            false => return Ok(()),
        }

        let (outputs, messages) = kernel.exec("date +%s", None).await?;
        assert_json_eq!(messages, json!([]));
        let timestamp = outputs.first().unwrap();
        match timestamp {
            Node::Integer(timestamp) => assert!(*timestamp > 1600000000),
            _ => bail!("Expected an integer"),
        }

        Ok(())
    }
}
<commit_msg>test(Bash microkernel): Add newline in to commands expecting output<commit_after>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for Bash
///
/// The `kernel-bash.sh` script relies on `/dev/stdin`, `/dev/stdout`,
/// and `/dev/stderr` so this kernel is not available on Windows.
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "bash-micro",
        &["Bash", "Shell"],
        true,
        false,
        false,
        ("bash", "*"),
        &["{{script}}"],
        include_file!("bash-kernel.sh"),
        &[],
        "{{name}}={{json}}",
        "echo ${{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        common::{
            eyre::{bail, Result},
            tokio,
        },
        stencila_schema::Node,
        KernelTrait,
    };
    use test_utils::{assert_json_eq, common::serde_json::json, skip_ci_os};

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        if skip_ci_os("windows", "test currently failing on windows") {
            return Ok(());
        }

        let mut kernel = new();
        match kernel.is_available().await {
            true => kernel.start_here().await?,
            false => return Ok(()),
        }

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a=2\necho $a\n", None).await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [2]);

        // Syntax error
        let (outputs, messages) = kernel.exec("if", None).await?;
        assert!(messages[0]
            .error_message
            .ends_with("syntax error: unexpected end of file"));
        assert_json_eq!(outputs, json!([]));

        // Runtime error
        let (outputs, messages) = kernel.exec("foo", None).await?;
        assert!(messages[0]
            .error_message
            .ends_with("foo: command not found"));
        assert_json_eq!(outputs, json!([]));

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_eq!(b, 3);

        // Use both variables
        let (outputs, messages) = kernel.exec("echo $a$b\n", None).await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [23]);

        Ok(())
    }

    #[tokio::test]
    async fn percent_escaping() -> Result<()> {
        if skip_ci_os("windows", "test currently failing on windows") {
            return Ok(());
        }

        let mut kernel = new();
        match kernel.is_available().await {
            true => kernel.start_here().await?,
            false => return Ok(()),
        }

        let (outputs, messages) = kernel.exec("date +%s", None).await?;
        assert_json_eq!(messages, json!([]));
        let timestamp = outputs.first().unwrap();
        match timestamp {
            Node::Integer(timestamp) => assert!(*timestamp > 1600000000),
            _ => bail!("Expected an integer"),
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use ra_ap_syntax::ast;

// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[derive(Debug, Eq, PartialEq)]
pub(crate) enum Import {
    /// use x as _;
    /// use x::*;
    Unnamed(String),
    /// use x::y;
    /// use x::y as z;
    Named { name: String, code: String },
}

impl Import {
    fn format(name: &str, path: &[String]) -> Import {
        let code;
        let joined_path = path.join("::");
        if path.last().map(String::as_str) == Some(name) {
            code = format!("use {};", joined_path);
        } else {
            code = format!("use {} as {};", joined_path, name);
        }
        if name == "_" || name == "*" {
            Import::Unnamed(code)
        } else {
            Import::Named {
                name: name.to_string(),
                code,
            }
        }
    }
}

pub(crate) fn use_tree_names_do(use_tree: &ast::UseTree, out: &mut impl FnMut(Import)) {
    fn process_use_tree(use_tree: &ast::UseTree, prefix: &[String], out: &mut impl FnMut(Import)) {
        if let Some(path) = use_tree.path() {
            // If we get ::self, ignore it and use what we've got so far.
            if path.segment().and_then(|segment| segment.kind())
                == Some(ast::PathSegmentKind::SelfKw)
            {
                if let Some(last) = prefix.last() {
                    out(Import::format(last, prefix));
                }
                return;
            }

            // Collect the components of `path`.
            let mut path = path;
            let mut path_parts = Vec::new();
            loop {
                if let Some(segment) = path.segment() {
                    if let Some(name_ref) = segment.name_ref() {
                        path_parts.push(name_ref.text().to_owned());
                    } else if let Some(token) = segment.crate_token() {
                        path_parts.push(token.text().to_owned());
                    }
                    if let Some(qualifier) = path.qualifier() {
                        path = qualifier;
                        continue;
                    }
                }
                break;
            }
            path_parts.reverse();

            // Combine the existing prefix with the new path components.
            let mut new_prefix = Vec::with_capacity(prefix.len() + path_parts.len());
            new_prefix.extend(prefix.iter().cloned());
            new_prefix.extend(path_parts.drain(..));

            // Recurse into any subtree.
            if let Some(tree_list) = use_tree.use_tree_list() {
                for subtree in tree_list.use_trees() {
                    process_use_tree(&subtree, &new_prefix, out);
                }
            } else if let Some(rename) = use_tree.rename() {
                if let Some(name) = ast::NameOwner::name(&rename) {
                    out(Import::format(&name.text(), &new_prefix));
                } else if let Some(underscore) = rename.underscore_token() {
                    out(Import::format(underscore.text(), &new_prefix));
                }
            } else if let Some(star_token) = use_tree.star_token() {
                new_prefix.push(star_token.text().to_owned());
                out(Import::format(star_token.text(), &new_prefix));
            } else if let Some(ident) = new_prefix.last() {
                out(Import::format(ident, &new_prefix));
            }
        }
    }

    process_use_tree(use_tree, &[], out);
}

#[cfg(test)]
mod tests {
    use super::{use_tree_names_do, Import};
    use ra_ap_syntax::ast;

    fn use_tree_names(code: &str) -> Vec<Import> {
        let mut out = Vec::new();
        let item = ast::Item::parse(code).unwrap();
        if let ast::Item::Use(use_stmt) = item {
            if let Some(use_tree) = use_stmt.use_tree() {
                use_tree_names_do(&use_tree, &mut |import| {
                    out.push(import);
                });
            }
        }
        out
    }

    fn unnamed(code: &str) -> Import {
        Import::Unnamed(code.to_owned())
    }

    fn named(name: &str, code: &str) -> Import {
        Import::Named {
            name: name.to_owned(),
            code: code.to_owned(),
        }
    }

    #[test]
    fn test_complex_tree() {
        assert_eq!(
            use_tree_names(
                "use std::collections::{self, hash_map::{HashMap}, HashSet as MyHashSet};"
            ),
            vec![
                named("collections", "use std::collections;"),
                named("HashMap", "use std::collections::hash_map::HashMap;"),
                named("MyHashSet", "use std::collections::HashSet as MyHashSet;")
            ]
        );
    }

    #[test]
    fn test_underscore() {
        assert_eq!(
            use_tree_names("use foo::bar::MyTrait as _;"),
            vec![unnamed("use foo::bar::MyTrait as _;"),]
        );
    }

    #[test]
    fn test_glob() {
        assert_eq!(
            use_tree_names("use foo::bar::*;"),
            vec![unnamed("use foo::bar::*;"),]
        );
    }
}
<commit_msg>Fix a clippy lint warning<commit_after>use ra_ap_syntax::ast;

// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[derive(Debug, Eq, PartialEq)]
pub(crate) enum Import {
    /// use x as _;
    /// use x::*;
    Unnamed(String),
    /// use x::y;
    /// use x::y as z;
    Named { name: String, code: String },
}

impl Import {
    fn format(name: &str, path: &[String]) -> Import {
        let code;
        let joined_path = path.join("::");
        if path.last().map(String::as_str) == Some(name) {
            code = format!("use {};", joined_path);
        } else {
            code = format!("use {} as {};", joined_path, name);
        }
        if name == "_" || name == "*" {
            Import::Unnamed(code)
        } else {
            Import::Named {
                name: name.to_string(),
                code,
            }
        }
    }
}

pub(crate) fn use_tree_names_do(use_tree: &ast::UseTree, out: &mut impl FnMut(Import)) {
    fn process_use_tree(use_tree: &ast::UseTree, prefix: &[String], out: &mut impl FnMut(Import)) {
        if let Some(path) = use_tree.path() {
            // If we get ::self, ignore it and use what we've got so far.
            if path.segment().and_then(|segment| segment.kind())
                == Some(ast::PathSegmentKind::SelfKw)
            {
                if let Some(last) = prefix.last() {
                    out(Import::format(last, prefix));
                }
                return;
            }

            // Collect the components of `path`.
            let mut path = path;
            let mut path_parts = Vec::new();
            loop {
                if let Some(segment) = path.segment() {
                    if let Some(name_ref) = segment.name_ref() {
                        path_parts.push(name_ref.text().to_owned());
                    } else if let Some(token) = segment.crate_token() {
                        path_parts.push(token.text().to_owned());
                    }
                    if let Some(qualifier) = path.qualifier() {
                        path = qualifier;
                        continue;
                    }
                }
                break;
            }
            path_parts.reverse();

            // Combine the existing prefix with the new path components.
            let mut new_prefix = Vec::with_capacity(prefix.len() + path_parts.len());
            new_prefix.extend(prefix.iter().cloned());
            new_prefix.append(&mut path_parts);

            // Recurse into any subtree.
            if let Some(tree_list) = use_tree.use_tree_list() {
                for subtree in tree_list.use_trees() {
                    process_use_tree(&subtree, &new_prefix, out);
                }
            } else if let Some(rename) = use_tree.rename() {
                if let Some(name) = ast::NameOwner::name(&rename) {
                    out(Import::format(&name.text(), &new_prefix));
                } else if let Some(underscore) = rename.underscore_token() {
                    out(Import::format(underscore.text(), &new_prefix));
                }
            } else if let Some(star_token) = use_tree.star_token() {
                new_prefix.push(star_token.text().to_owned());
                out(Import::format(star_token.text(), &new_prefix));
            } else if let Some(ident) = new_prefix.last() {
                out(Import::format(ident, &new_prefix));
            }
        }
    }

    process_use_tree(use_tree, &[], out);
}

#[cfg(test)]
mod tests {
    use super::{use_tree_names_do, Import};
    use ra_ap_syntax::ast;

    fn use_tree_names(code: &str) -> Vec<Import> {
        let mut out = Vec::new();
        let item = ast::Item::parse(code).unwrap();
        if let ast::Item::Use(use_stmt) = item {
            if let Some(use_tree) = use_stmt.use_tree() {
                use_tree_names_do(&use_tree, &mut |import| {
                    out.push(import);
                });
            }
        }
        out
    }

    fn unnamed(code: &str) -> Import {
        Import::Unnamed(code.to_owned())
    }

    fn named(name: &str, code: &str) -> Import {
        Import::Named {
            name: name.to_owned(),
            code: code.to_owned(),
        }
    }

    #[test]
    fn test_complex_tree() {
        assert_eq!(
            use_tree_names(
                "use std::collections::{self, hash_map::{HashMap}, HashSet as MyHashSet};"
            ),
            vec![
                named("collections", "use std::collections;"),
                named("HashMap", "use std::collections::hash_map::HashMap;"),
                named("MyHashSet", "use std::collections::HashSet as MyHashSet;")
            ]
        );
    }

    #[test]
    fn test_underscore() {
        assert_eq!(
            use_tree_names("use foo::bar::MyTrait as _;"),
            vec![unnamed("use foo::bar::MyTrait as _;"),]
        );
    }

    #[test]
    fn test_glob() {
        assert_eq!(
            use_tree_names("use foo::bar::*;"),
            vec![unnamed("use foo::bar::*;"),]
        );
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, 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 crate::Error;
use futures::future::Future;
use slog_scope::error;
use std::collections::BTreeMap;
use std::process::exit;
use std::sync::Arc;
use structopt::StructOpt;

use crate::logger::logger_init;

pub fn get_zip_codes_from_admins(admins: &[Arc<places::admin::Admin>]) -> Vec<String> {
    let level = admins.iter().fold(0, |level, adm| {
        if adm.level > level && !adm.zip_codes.is_empty() {
            adm.level
        } else {
            level
        }
    });
    if level == 0 {
        return vec![];
    }
    admins
        .iter()
        .filter(|adm| adm.level == level)
        .flat_map(|adm| adm.zip_codes.iter().cloned())
        .collect()
}

pub const ADMIN_MAX_WEIGHT: f64 = 1_400_000_000.; // China's population

/// normalize the admin weight for it to be in [0, 1]
pub fn normalize_admin_weight(admins: &mut [places::admin::Admin]) {
    for admin in admins {
        admin.weight = normalize_weight(admin.weight, ADMIN_MAX_WEIGHT);
    }
}

/// normalize the weight for it to be in [0, 1]
pub fn normalize_weight(weight: f64, max_weight: f64) -> f64 {
    let w = weight / max_weight;
    if w > 1. {
        1.
    } else {
        w
    }
}

pub async fn wrapped_launch_async<O, F, Fut>(run: F) -> Result<(), Error>
where
    O: StructOpt,
    F: FnOnce(O) -> Fut,
    Fut: Future<Output = Result<(), Error>>,
{
    let (guard, _) = logger_init();
    guard.cancel_reset(); // The guard should not be dropped before the Future has been resolved
    if let Err(err) = run(O::from_args()).await {
        for cause in err.iter_chain() {
            error!("{}", cause);
        }
        Err(err)
    } else {
        Ok(())
    }
}

pub async fn launch_async<O, F, Fut>(run: F)
where
    O: StructOpt,
    F: FnOnce(O) -> Fut,
    Fut: Future<Output = Result<(), Error>>,
{
    if wrapped_launch_async(run).await.is_err() {
        // we wrap the real stuff in another method to std::exit after
        // the destruction of the logger (so we won't loose any messages)
        exit(1);
    }
}

pub fn wrapped_launch_run<O, F>(run: F) -> Result<(), Error>
where
    F: FnOnce(O) -> Result<(), Error>,
    O: StructOpt,
{
    let _guard = logger_init();
    if let Err(err) = run(O::from_args()) {
        for cause in err.iter_chain() {
            error!("{}", cause);
        }
        Err(err)
    } else {
        Ok(())
    }
}

pub fn launch_run<O, F>(run: F)
where
    F: FnOnce(O) -> Result<(), Error>,
    O: StructOpt,
{
    if wrapped_launch_run(run).is_err() {
        // we wrap the real stuff in another method to std::exit after
        // the destruction of the logger (so we won't loose any messages)
        exit(1);
    }
}

pub fn get_country_code(codes: &BTreeMap<String, String>) -> Option<String> {
    codes.get("ISO3166-1:alpha2").cloned()
}

pub fn find_country_codes<'a>(
    admins: impl Iterator<Item = &'a places::admin::Admin>,
) -> Vec<String> {
    admins.filter_map(|a| get_country_code(&a.codes)).collect()
}
<commit_msg>Ensure the logger is flushed before the process exits<commit_after>// Copyright © 2016, 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 crate::Error;
use futures::future::Future;
use slog_scope::error;
use std::collections::BTreeMap;
use std::process::exit;
use std::sync::Arc;
use structopt::StructOpt;

use crate::logger::logger_init;

pub fn get_zip_codes_from_admins(admins: &[Arc<places::admin::Admin>]) -> Vec<String> {
    let level = admins.iter().fold(0, |level, adm| {
        if adm.level > level && !adm.zip_codes.is_empty() {
            adm.level
        } else {
            level
        }
    });
    if level == 0 {
        return vec![];
    }
    admins
        .iter()
        .filter(|adm| adm.level == level)
        .flat_map(|adm| adm.zip_codes.iter().cloned())
        .collect()
}

pub const ADMIN_MAX_WEIGHT: f64 = 1_400_000_000.; // China's population

/// normalize the admin weight for it to be in [0, 1]
pub fn normalize_admin_weight(admins: &mut [places::admin::Admin]) {
    for admin in admins {
        admin.weight = normalize_weight(admin.weight, ADMIN_MAX_WEIGHT);
    }
}

/// normalize the weight for it to be in [0, 1]
pub fn normalize_weight(weight: f64, max_weight: f64) -> f64 {
    let w = weight / max_weight;
    if w > 1. {
        1.
    } else {
        w
    }
}

pub async fn wrapped_launch_async<O, F, Fut>(run: F) -> Result<(), Error>
where
    O: StructOpt,
    F: FnOnce(O) -> Fut,
    Fut: Future<Output = Result<(), Error>>,
{
    let (guard, _) = logger_init();
    let res = if let Err(err) = run(O::from_args()).await {
        for cause in err.iter_chain() {
            error!("{}", cause);
        }
        Err(err)
    } else {
        Ok(())
    };

    // Ensure the logger persists until the future is resolved
    // and is flushed before the process exits.
    drop(guard);
    res
}

pub async fn launch_async<O, F, Fut>(run: F)
where
    O: StructOpt,
    F: FnOnce(O) -> Fut,
    Fut: Future<Output = Result<(), Error>>,
{
    if wrapped_launch_async(run).await.is_err() {
        // we wrap the real stuff in another method to std::exit after
        // the destruction of the logger (so we won't loose any messages)
        exit(1);
    }
}

pub fn wrapped_launch_run<O, F>(run: F) -> Result<(), Error>
where
    F: FnOnce(O) -> Result<(), Error>,
    O: StructOpt,
{
    let _guard = logger_init();
    if let Err(err) = run(O::from_args()) {
        for cause in err.iter_chain() {
            error!("{}", cause);
        }
        Err(err)
    } else {
        Ok(())
    }
}

pub fn launch_run<O, F>(run: F)
where
    F: FnOnce(O) -> Result<(), Error>,
    O: StructOpt,
{
    if wrapped_launch_run(run).is_err() {
        // we wrap the real stuff in another method to std::exit after
        // the destruction of the logger (so we won't loose any messages)
        exit(1);
    }
}

pub fn get_country_code(codes: &BTreeMap<String, String>) -> Option<String> {
    codes.get("ISO3166-1:alpha2").cloned()
}

pub fn find_country_codes<'a>(
    admins: impl Iterator<Item = &'a places::admin::Admin>,
) -> Vec<String> {
    admins.filter_map(|a| get_country_code(&a.codes)).collect()
}
<|endoftext|>