<commit_before>use async_input::AsyncInput;
use base::*;
use crossover;
use downmixer;
use filters::*;
use output;
use std;
use std::cmp;
use time::*;
use ui;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    gain: ui::Gain,
}

fn get_multiplier(input_gain: ui::Gain, output_gain: ui::Gain) -> f32 {
    10f32.powf((input_gain.db + output_gain.db) / 20.0)
}

impl InputMixer {
    fn new(input: AsyncInput, gain: ui::Gain) -> InputMixer {
        InputMixer {
            input: input,
            current_frame: Frame::new(1.0, Time::zero(), 0),
            current_frame_pos: 0,
            gain: gain,
        }
    }

    fn set_gain(&mut self, gain: ui::Gain) {
        self.gain = gain;
    }

    fn receive_frame(&mut self, deadline: Time, stream_time: Time) -> Result<bool> {
        loop {
            match self.input.read(deadline - Time::now())? {
                None => return Ok(false),
                Some(frame) => {
                    // If the frame is too old then drop it.
                    if frame.end_timestamp() < stream_time {
                        println!("WARNING: Dropping old frame.");
                        continue;
                    }
                    self.current_frame = frame;
                    self.current_frame_pos = 0;
                    return Ok(true);
                }
            }
        }
    }

    fn min_delay(&self) -> TimeDelta {
        self.input.min_delay()
    }

    fn get_frame(
        &mut self,
        deadline: Time,
        stream_time: Time,
        out_gain: ui::Gain,
    ) -> Result<Option<Frame>> {
        if !self.receive_frame(deadline, stream_time)? {
            return Ok(None);
        }
        let mut frame = Frame::new(1.0, Time::zero(), 0);
        std::mem::swap(&mut frame, &mut self.current_frame);
        self.current_frame_pos = 0;

        let multiplier = get_multiplier(self.gain, out_gain);
        for (_channel, pcm) in frame.iter_channels() {
            for i in 0..pcm.len() {
                pcm[i] *= multiplier;
            }
        }

        Ok(Some(frame))
    }

    fn mix_into(
        &mut self,
        mixed_frame: &mut Frame,
        deadline: Time,
        out_gain: ui::Gain,
    ) -> Result<bool> {
        let multiplier = get_multiplier(self.gain, out_gain);
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                if !self.receive_frame(deadline, mixed_frame.timestamp)? {
                    return Ok(pos > 0);
                }
            }

            let samples = cmp::min(
                self.current_frame.len() - self.current_frame_pos,
                mixed_frame.len() - pos,
            );

            for (c, src_pcm) in self.current_frame.iter_channels() {
                let dst_pcm = mixed_frame.ensure_channel(c);
                for i in 0..samples {
                    dst_pcm[pos + i] += multiplier * src_pcm[self.current_frame_pos + i];
                }
            }

            self.current_frame_pos += samples;
            pos += samples;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    fir_filter: Option<Box<StreamFilter>>,
    subwoofer_config: Option<ui::SubwooferConfig>,

    drc_enabled: bool,
    subwoofer_enabled: bool,

    downmixer: downmixer::Downmixer,
    crossover: Option<crossover::CrossoverFilter>,
    ui_msg_receiver: ui::UiMessageReceiver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        out_channels: PerChannel<bool>,
        fir_filter: Option<Box<StreamFilter>>,
        subwoofer_config: Option<ui::SubwooferConfig>,
        shared_state: &ui::SharedState,
    ) -> Box<output::Output> {
        let enable_drc = shared_state.lock().state().enable_drc.unwrap_or(false);
        let enable_subwoofer = shared_state
            .lock()
            .state()
            .enable_subwoofer
            .unwrap_or(false);
        let mut result = Box::new(FilteredOutput {
            output: output,
            fir_filter: fir_filter,
            subwoofer_config: subwoofer_config,

            drc_enabled: enable_drc,
            subwoofer_enabled: enable_subwoofer,

            downmixer: downmixer::Downmixer::new(out_channels),
            crossover: None,
            ui_msg_receiver: shared_state.lock().add_observer(),
        });
        result.update_crossover();
        result
    }

    fn update_crossover(&mut self) {
        self.crossover = match (self.subwoofer_enabled, self.subwoofer_config) {
            (false, _) => None,
            (true, None) => None,
            (
                true,
                Some(ui::SubwooferConfig {
                    crossover_frequency,
                }),
            ) => Some(crossover::CrossoverFilter::new(crossover_frequency)),
        };
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, frame: Frame) -> Result<()> {
        let mut need_reset = false;
        for msg in self.ui_msg_receiver.try_iter() {
            match msg {
                ui::UiMessage::SetEnableDrc { enable } => {
                    self.drc_enabled = enable;
                    need_reset = true;
                }
                ui::UiMessage::SetEnableSubwoofer { enable } => {
                    self.subwoofer_enabled = enable;
                    need_reset = true;
                }
                _ => (),
            }
        }

        if need_reset {
            self.update_crossover();
            self.fir_filter.as_mut().map(|f| f.reset());
        }

        let frame = self.downmixer.process(frame);

        let frame = match self.crossover.as_mut() {
            Some(c) => c.apply(frame),
            None => frame,
        };

        let frame = match (self.drc_enabled, self.fir_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> f64 {
        self.output.sample_rate()
    }

    fn min_delay(&self) -> TimeDelta {
        self.output.min_delay()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 1200;
const STANDBY_SECONDS: i64 = 3600;

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: f64,
    period_duration: TimeDelta,
    shared_state: ui::SharedState,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = {
        let mut pos = 0;
        let state = shared_state.lock();
        inputs
            .drain(..)
            .map(|i| {
                let gain = state.state().inputs[pos].gain;
                pos += 1;
                Box::new(InputMixer::new(i, gain))
            })
            .collect()
    };

    let mut output_gain = shared_state.lock().volume();

    let mut last_data_time = Time::now();
    let mut state = ui::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        MultichannelFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;

    let mut stream_start_time = Time::now();
    let mut stream_pos: i64 = 0;

    loop {
        let min_input_delay = mixers
            .iter()
            .fold(TimeDelta::zero(), |max, i| cmp::max(max, i.min_delay()));

        let stream_time = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mix_delay = min_input_delay + period_duration * 2;
        let mix_deadline = stream_time + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!("ERROR: Mixer missed deadline. Resetting stream.");
            stream_start_time = now;
            stream_pos = 0;
            continue;
        }

        let mut frame = Frame::new(sample_rate, stream_time, period_size);
        let mut have_data = false;

        if exclusive_mux_mode {
            for m in mixers.iter_mut() {
                match m.get_frame(mix_deadline, stream_time, output_gain)? {
                    Some(f) => {
                        frame = f;
                        have_data = true;
                        break;
                    }
                    None => (),
                }
            }
            stream_start_time = frame.end_timestamp();
            stream_pos = 0;
        } else {
            for m in mixers.iter_mut() {
                have_data |= try!(m.mix_into(&mut frame, mix_deadline, output_gain));
            }
            stream_pos += frame.len() as i64;
        }

        let new_state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                ui::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            frame = loudness_filter.apply(frame);
            frame = crossfeed_filter.apply(frame);

            frame.timestamp +=
                mix_delay + period_duration * 4 + outputs[selected_output].min_delay();
            try!(outputs[selected_output].write(frame));
        } else {
            std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
            stream_start_time = Time::now() - mix_delay;
            stream_pos = 0;
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    output_gain = volume;
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable: _ } => (),
                ui::UiMessage::SetEnableSubwoofer { enable: _ } => (),
                ui::UiMessage::SetCrossfeed { config } => {
                    crossfeed_filter.set_params(config.get_level(), config.delay_ms);
                }
                ui::UiMessage::SetMuxMode { mux_mode } => {
                    exclusive_mux_mode = mux_mode == ui::MuxMode::Exclusive;
                }
            }
        }
    }
}
<commit_msg>Fix output deactivation<commit_after>use async_input::AsyncInput;
use base::*;
use crossover;
use downmixer;
use filters::*;
use output;
use std;
use std::cmp;
use time::*;
use ui;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    gain: ui::Gain,
}

fn get_multiplier(input_gain: ui::Gain, output_gain: ui::Gain) -> f32 {
    10f32.powf((input_gain.db + output_gain.db) / 20.0)
}

impl InputMixer {
    fn new(input: AsyncInput, gain: ui::Gain) -> InputMixer {
        InputMixer {
            input: input,
            current_frame: Frame::new(1.0, Time::zero(), 0),
            current_frame_pos: 0,
            gain: gain,
        }
    }

    fn set_gain(&mut self, gain: ui::Gain) {
        self.gain = gain;
    }

    fn receive_frame(&mut self, deadline: Time, stream_time: Time) -> Result<bool> {
        loop {
            match self.input.read(deadline - Time::now())? {
                None => return Ok(false),
                Some(frame) => {
                    // If the frame is too old then drop it.
                    if frame.end_timestamp() < stream_time {
                        println!("WARNING: Dropping old frame.");
                        continue;
                    }
                    self.current_frame = frame;
                    self.current_frame_pos = 0;
                    return Ok(true);
                }
            }
        }
    }

    fn min_delay(&self) -> TimeDelta {
        self.input.min_delay()
    }

    fn get_frame(
        &mut self,
        deadline: Time,
        stream_time: Time,
        out_gain: ui::Gain,
    ) -> Result<Option<Frame>> {
        if !self.receive_frame(deadline, stream_time)? {
            return Ok(None);
        }
        let mut frame = Frame::new(1.0, Time::zero(), 0);
        std::mem::swap(&mut frame, &mut self.current_frame);
        self.current_frame_pos = 0;

        let multiplier = get_multiplier(self.gain, out_gain);
        for (_channel, pcm) in frame.iter_channels() {
            for i in 0..pcm.len() {
                pcm[i] *= multiplier;
            }
        }

        Ok(Some(frame))
    }

    fn mix_into(
        &mut self,
        mixed_frame: &mut Frame,
        deadline: Time,
        out_gain: ui::Gain,
    ) -> Result<bool> {
        let multiplier = get_multiplier(self.gain, out_gain);
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                if !self.receive_frame(deadline, mixed_frame.timestamp)? {
                    return Ok(pos > 0);
                }
            }

            let samples = cmp::min(
                self.current_frame.len() - self.current_frame_pos,
                mixed_frame.len() - pos,
            );

            for (c, src_pcm) in self.current_frame.iter_channels() {
                let dst_pcm = mixed_frame.ensure_channel(c);
                for i in 0..samples {
                    dst_pcm[pos + i] += multiplier * src_pcm[self.current_frame_pos + i];
                }
            }

            self.current_frame_pos += samples;
            pos += samples;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    fir_filter: Option<Box<StreamFilter>>,
    subwoofer_config: Option<ui::SubwooferConfig>,

    drc_enabled: bool,
    subwoofer_enabled: bool,

    downmixer: downmixer::Downmixer,
    crossover: Option<crossover::CrossoverFilter>,
    ui_msg_receiver: ui::UiMessageReceiver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        out_channels: PerChannel<bool>,
        fir_filter: Option<Box<StreamFilter>>,
        subwoofer_config: Option<ui::SubwooferConfig>,
        shared_state: &ui::SharedState,
    ) -> Box<output::Output> {
        let enable_drc = shared_state.lock().state().enable_drc.unwrap_or(false);
        let enable_subwoofer = shared_state
            .lock()
            .state()
            .enable_subwoofer
            .unwrap_or(false);
        let mut result = Box::new(FilteredOutput {
            output: output,
            fir_filter: fir_filter,
            subwoofer_config: subwoofer_config,

            drc_enabled: enable_drc,
            subwoofer_enabled: enable_subwoofer,

            downmixer: downmixer::Downmixer::new(out_channels),
            crossover: None,
            ui_msg_receiver: shared_state.lock().add_observer(),
        });
        result.update_crossover();
        result
    }

    fn update_crossover(&mut self) {
        self.crossover = match (self.subwoofer_enabled, self.subwoofer_config) {
            (false, _) => None,
            (true, None) => None,
            (
                true,
                Some(ui::SubwooferConfig {
                    crossover_frequency,
                }),
            ) => Some(crossover::CrossoverFilter::new(crossover_frequency)),
        };
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, frame: Frame) -> Result<()> {
        let mut need_reset = false;
        for msg in self.ui_msg_receiver.try_iter() {
            match msg {
                ui::UiMessage::SetEnableDrc { enable } => {
                    self.drc_enabled = enable;
                    need_reset = true;
                }
                ui::UiMessage::SetEnableSubwoofer { enable } => {
                    self.subwoofer_enabled = enable;
                    need_reset = true;
                }
                _ => (),
            }
        }

        if need_reset {
            self.update_crossover();
            self.fir_filter.as_mut().map(|f| f.reset());
        }

        let frame = self.downmixer.process(frame);

        let frame = match self.crossover.as_mut() {
            Some(c) => c.apply(frame),
            None => frame,
        };

        let frame = match (self.drc_enabled, self.fir_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> f64 {
        self.output.sample_rate()
    }

    fn min_delay(&self) -> TimeDelta {
        self.output.min_delay()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 1200;
const STANDBY_SECONDS: i64 = 3600;

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: f64,
    period_duration: TimeDelta,
    shared_state: ui::SharedState,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = {
        let mut pos = 0;
        let state = shared_state.lock();
        inputs
            .drain(..)
            .map(|i| {
                let gain = state.state().inputs[pos].gain;
                pos += 1;
                Box::new(InputMixer::new(i, gain))
            })
            .collect()
    };

    let mut output_gain = shared_state.lock().volume();

    let mut last_data_time = Time::now();
    let mut state = ui::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        MultichannelFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;

    let mut stream_start_time = Time::now();
    let mut stream_pos: i64 = 0;

    loop {
        let min_input_delay = mixers
            .iter()
            .fold(TimeDelta::zero(), |max, i| cmp::max(max, i.min_delay()));

        let stream_time = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mix_delay = min_input_delay + period_duration * 2;
        let mix_deadline = stream_time + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!("ERROR: Mixer missed deadline. Resetting stream.");
            stream_start_time = now;
            stream_pos = 0;
            continue;
        }

        let mut frame = Frame::new(sample_rate, stream_time, period_size);
        let mut have_data = false;

        if exclusive_mux_mode {
            for m in mixers.iter_mut() {
                match m.get_frame(mix_deadline, stream_time, output_gain)? {
                    Some(f) => {
                        frame = f;
                        have_data = true;
                        break;
                    }
                    None => (),
                }
            }
            stream_start_time = frame.end_timestamp();
            stream_pos = 0;
        } else {
            for m in mixers.iter_mut() {
                have_data |= try!(m.mix_into(&mut frame, mix_deadline, output_gain));
            }
            stream_pos += frame.len() as i64;
        }

        let new_state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                ui::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            frame = loudness_filter.apply(frame);
            frame = crossfeed_filter.apply(frame);

            frame.timestamp +=
                mix_delay + period_duration * 4 + outputs[selected_output].min_delay();
            try!(outputs[selected_output].write(frame));
        } else {
            std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
            stream_start_time = Time::now() - mix_delay;
            stream_pos = 0;
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[selected_output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    output_gain = volume;
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable: _ } => (),
                ui::UiMessage::SetEnableSubwoofer { enable: _ } => (),
                ui::UiMessage::SetCrossfeed { config } => {
                    crossfeed_filter.set_params(config.get_level(), config.delay_ms);
                }
                ui::UiMessage::SetMuxMode { mux_mode } => {
                    exclusive_mux_mode = mux_mode == ui::MuxMode::Exclusive;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    // If a piece moves off of a hex, and that hex gets removed, the last move will not have a
    // "from" field, only a "to" field
    pub last_move: Option<(Option<FieldCoord>, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
}

#[derive(PartialEq)]
pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        match self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            Some(neighbor) => {
                let f = (coord.f + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
            None => {}
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    /*
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    */
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        if HexCoord::is_valid_coord(x, y) {
            let coord = HexCoord::new(x, y);
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /*
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<(u32, HexCoord)> {
        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        neighbors
            .iter()
            .enumerate()
            .filter(|&(_, &(x, y))| HexCoord::is_valid_coord(x, y))
            .filter_map(|(i, &(x, y))| {
                let coord = HexCoord::new(x, y);
                if self.is_hex_extant(&coord) {
                    Some((i as u32, coord))
                } else {
                    None
                }
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in self.get_hex_neighbors(coord) {
            let f = (i + 3) % 6;
            neighbors.push(neighbor.to_field(f));
        }
        neighbors
    }
    */
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    /*
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
    */
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if HexCoord::is_valid_coord(x, y) {
                    let coord = HexCoord::new(x, y);
                    if self.is_hex_extant(&coord) {
                        coords.push(coord);
                    }
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    pub fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn is_white(&self) -> bool {
        self.f % 2 == 1
    }
    pub fn is_black(&self) -> bool {
        self.f % 2 == 0
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    pub fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<commit_msg>Add back rest of Model, remove get_hex_neighbors<commit_after>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    // If a piece moves off of a hex, and that hex gets removed, the last move will not have a
    // "from" field, only a "to" field
    pub last_move: Option<(Option<FieldCoord>, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
}

#[derive(PartialEq)]
pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        match self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            Some(neighbor) => {
                let f = (coord.f + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
            None => {}
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        if HexCoord::is_valid_coord(x, y) {
            let coord = HexCoord::new(x, y);
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for f in 0..6 {
            if let Some(neighbor) = self.get_hex_neighbor(coord, f) {
                neighbors.push(neighbor.to_field((f + 3) % 6));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if HexCoord::is_valid_coord(x, y) {
                    let coord = HexCoord::new(x, y);
                    if self.is_hex_extant(&coord) {
                        coords.push(coord);
                    }
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    pub fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn is_white(&self) -> bool {
        self.f % 2 == 1
    }
    pub fn is_black(&self) -> bool {
        self.f % 2 == 0
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    pub fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<|endoftext|>


<commit_before>use http::server::request::{AbsolutePath};
use regex::Regex;

use iron::{Iron, Middleware, Request, Response, Alloy, Furnace};
use iron::middleware::{Status, Continue, Unwind};

#[deriving(Clone)]
pub struct Mount<F> {
    route: String,
    matches: Regex,
    iron: Iron<F>
}

impl<F> Mount<F> {
    pub fn new(route: &str, iron: Iron<F>) -> Mount<F> {
        Mount {
            route: route.to_string(),
            iron: iron,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

<commit_msg>(feat) Made Mount a Middleware.<commit_after>use http::server::request::{AbsolutePath};
use regex::Regex;

use iron::{Iron, Middleware, Request, Response, Alloy, Furnace};
use iron::middleware::{Status, Continue, Unwind};

#[deriving(Clone)]
pub struct Mount<F> {
    route: String,
    matches: Regex,
    iron: Iron<F>
}

impl<F> Mount<F> {
    pub fn new(route: &str, iron: Iron<F>) -> Mount<F> {
        Mount {
            route: route.to_string(),
            iron: iron,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

impl<F: Furnace> Middleware for Mount<F> {
    fn enter(&mut self,
             req: &mut Request,
             res: &mut Response,
             alloy: &mut Alloy) -> Status {
        // This method is ugly, but it is hard to make it pretty
        // because we can't both borrow path from inside of request
        // while allowing furnace.forge to borrow it as mutable.

        match req.request_uri {
           AbsolutePath(ref path) => {
               // Short circuit if we don't match.
                if !self.matches.is_match(path.as_slice()) {
                    return Continue;
                }
           },
           // Short circuit if this is not an AbsolutePath.
           _ => { return Continue; }
        }

        // We are a match, so fire off to our child instance.
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = path.as_slice().slice_from(self.route.len()).to_string();
            },
            // Absolutely cannot happen because of our previous check,
            // but this is here just to be careful.
            _ => { return Continue; }
        } // Previous borrow of req ends here.

        // So we can borrow it again here.
        self.iron.furnace.forge(req, res, Some(alloy));

        // And repair the damage here, for future middleware
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = self.route.clone().append(path.as_slice());
            },
            // This really, really should never happen.
            _ => { fail!("The impossible happened."); }
        }

        // We dispatched the request, so Unwind.
        Unwind
    }
}

<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem;
use std::str;
use std::ptr;
use std::slice;

use types::AresError;
use utils::ares_error;

/// The result of a successful NAPTR lookup.
pub struct NAPTRResults {
    naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply,
}

/// The contents of a single NAPTR record.
pub struct NAPTRResult<'a> {
    // A single result - reference into a `NAPTRResults`.
    naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply,
    phantom: PhantomData<&'a NAPTRResults>,
}

impl NAPTRResults {
    #[cfg(feature = "old-cares")]
    pub fn parse_from(_data: &[u8]) -> Result<NAPTRResult, AresError> {
        panic!("NAPTR parsing not supported");
    }

    /// Obtain a `NAPTRResults` from the response to an NAPTR lookup.
    #[cfg(not(feature = "old-cares"))]
    pub fn parse_from(data: &[u8]) -> Result<NAPTRResults, AresError> {
        let mut naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply =
            ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_naptr_reply(
                data.as_ptr(),
                data.len() as libc::c_int,
                &mut naptr_reply)
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let naptr_result = NAPTRResults::new(naptr_reply);
            Ok(naptr_result)
        }
    }

    fn new(
        reply: *mut c_ares_sys::Struct_ares_naptr_reply) -> NAPTRResults {
        NAPTRResults {
            naptr_reply: reply,
        }
    }

    /// Returns an iterator over the `NAPTRResult` values in this
    /// `NAPTRResults`.
    pub fn iter(&self) -> NAPTRResultsIterator {
        NAPTRResultsIterator {
            next: self.naptr_reply,
            phantom: PhantomData,
        }
    }
}

pub struct NAPTRResultsIterator<'a> {
    next: *mut c_ares_sys::Struct_ares_naptr_reply,
    phantom: PhantomData<&'a NAPTRResults>,
}

impl<'a> Iterator for NAPTRResultsIterator<'a> {
    type Item = NAPTRResult<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let naptr_reply = self.next;
        if naptr_reply.is_null() {
            None
        } else {
            self.next = unsafe { (*naptr_reply).next };
            let naptr_result = NAPTRResult {
                naptr_reply: naptr_reply,
                phantom: PhantomData,
            };
            Some(naptr_result)
        }
    }
}

impl<'a> IntoIterator for &'a NAPTRResults {
    type Item = NAPTRResult<'a>;
    type IntoIter = NAPTRResultsIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        NAPTRResultsIterator {
            next: self.naptr_reply,
            phantom: PhantomData,
        }
    }
}

impl Drop for NAPTRResults {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_data(self.naptr_reply as *mut libc::c_void);
        }
    }
}

unsafe impl Send for NAPTRResults { }
unsafe impl Sync for NAPTRResults { }
unsafe impl<'a> Send for NAPTRResult<'a> { }
unsafe impl<'a> Sync for NAPTRResult<'a> { }
unsafe impl<'a> Send for NAPTRResultsIterator<'a> { }
unsafe impl<'a> Sync for NAPTRResultsIterator<'a> { }

impl<'a> NAPTRResult<'a> {
    /// Returns the flags in this `NAPTRResult`.
    pub fn flags(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).flags as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the service name in this `NAPTRResult`.
    pub fn service_name(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).service as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the regular expression in this `NAPTRResult`.
    pub fn reg_exp(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).regexp as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the replacement pattern in this `NAPTRResult`.
    pub fn replacement_pattern(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr((*self.naptr_reply).replacement);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the order value in this `NAPTRResult`.
    pub fn order(&self) -> u16 {
        unsafe { (*self.naptr_reply).order }
    }

    /// Returns the preference value in this `NAPTRResult`.
    pub fn preference(&self) -> u16 {
        unsafe { (*self.naptr_reply).preference }
    }
}

pub unsafe extern "C" fn query_naptr_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<NAPTRResults, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let data = slice::from_raw_parts(abuf, alen as usize);
        NAPTRResults::parse_from(data)
    };
    let handler: Box<F> = mem::transmute(arg);
    handler(result);
}
<commit_msg>NAPTRRestults, not NAPTRResult<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem;
use std::str;
use std::ptr;
use std::slice;

use types::AresError;
use utils::ares_error;

/// The result of a successful NAPTR lookup.
pub struct NAPTRResults {
    naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply,
}

/// The contents of a single NAPTR record.
pub struct NAPTRResult<'a> {
    // A single result - reference into a `NAPTRResults`.
    naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply,
    phantom: PhantomData<&'a NAPTRResults>,
}

impl NAPTRResults {
    #[cfg(feature = "old-cares")]
    pub fn parse_from(_data: &[u8]) -> Result<NAPTRResults, AresError> {
        panic!("NAPTR parsing not supported");
    }

    /// Obtain a `NAPTRResults` from the response to an NAPTR lookup.
    #[cfg(not(feature = "old-cares"))]
    pub fn parse_from(data: &[u8]) -> Result<NAPTRResults, AresError> {
        let mut naptr_reply: *mut c_ares_sys::Struct_ares_naptr_reply =
            ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_naptr_reply(
                data.as_ptr(),
                data.len() as libc::c_int,
                &mut naptr_reply)
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let naptr_result = NAPTRResults::new(naptr_reply);
            Ok(naptr_result)
        }
    }

    fn new(
        reply: *mut c_ares_sys::Struct_ares_naptr_reply) -> NAPTRResults {
        NAPTRResults {
            naptr_reply: reply,
        }
    }

    /// Returns an iterator over the `NAPTRResult` values in this
    /// `NAPTRResults`.
    pub fn iter(&self) -> NAPTRResultsIterator {
        NAPTRResultsIterator {
            next: self.naptr_reply,
            phantom: PhantomData,
        }
    }
}

pub struct NAPTRResultsIterator<'a> {
    next: *mut c_ares_sys::Struct_ares_naptr_reply,
    phantom: PhantomData<&'a NAPTRResults>,
}

impl<'a> Iterator for NAPTRResultsIterator<'a> {
    type Item = NAPTRResult<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let naptr_reply = self.next;
        if naptr_reply.is_null() {
            None
        } else {
            self.next = unsafe { (*naptr_reply).next };
            let naptr_result = NAPTRResult {
                naptr_reply: naptr_reply,
                phantom: PhantomData,
            };
            Some(naptr_result)
        }
    }
}

impl<'a> IntoIterator for &'a NAPTRResults {
    type Item = NAPTRResult<'a>;
    type IntoIter = NAPTRResultsIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        NAPTRResultsIterator {
            next: self.naptr_reply,
            phantom: PhantomData,
        }
    }
}

impl Drop for NAPTRResults {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_data(self.naptr_reply as *mut libc::c_void);
        }
    }
}

unsafe impl Send for NAPTRResults { }
unsafe impl Sync for NAPTRResults { }
unsafe impl<'a> Send for NAPTRResult<'a> { }
unsafe impl<'a> Sync for NAPTRResult<'a> { }
unsafe impl<'a> Send for NAPTRResultsIterator<'a> { }
unsafe impl<'a> Sync for NAPTRResultsIterator<'a> { }

impl<'a> NAPTRResult<'a> {
    /// Returns the flags in this `NAPTRResult`.
    pub fn flags(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).flags as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the service name in this `NAPTRResult`.
    pub fn service_name(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).service as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the regular expression in this `NAPTRResult`.
    pub fn reg_exp(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(
                (*self.naptr_reply).regexp as *const libc::c_char);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the replacement pattern in this `NAPTRResult`.
    pub fn replacement_pattern(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr((*self.naptr_reply).replacement);
            str::from_utf8(c_str.to_bytes()).unwrap()
        }
    }

    /// Returns the order value in this `NAPTRResult`.
    pub fn order(&self) -> u16 {
        unsafe { (*self.naptr_reply).order }
    }

    /// Returns the preference value in this `NAPTRResult`.
    pub fn preference(&self) -> u16 {
        unsafe { (*self.naptr_reply).preference }
    }
}

pub unsafe extern "C" fn query_naptr_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<NAPTRResults, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let data = slice::from_raw_parts(abuf, alen as usize);
        NAPTRResults::parse_from(data)
    };
    let handler: Box<F> = mem::transmute(arg);
    handler(result);
}
<|endoftext|>


<commit_before>//! A trait for a LiDAR point
//!
//! This is is a catchall trait that has a bunch of optional fields. This lets sources choose what
//! values to fill in, and sinks choose what values to pay attention to.

use std::u16;

use Result;

/// A point.
pub trait Point where Self: Sized {
    /// The x dimension of a point. All points must have these.
    fn x(&self) -> f64;

    /// The y dimension of a point. All points must have these.
    fn y(&self) -> f64;

    /// The z dimension of a point. All points must have these.
    fn z(&self) -> f64;

    /// This is the intensity of the backscattered energy, as detected by the LiDAR sensor. Since
    /// each sensor has its own dynamic range, an intensity value is actually three values — the
    /// intensity value itself, the minimum possible value, and the maximum possible value.
    fn intensity(&self) -> Intensity;

    /// The return number of this point.
    fn return_number(&self) -> Option<usize>;

    /// The total number of returns in the pulse of this point.
    fn number_of_returns(&self) -> Option<usize>;

    /// The direction that the scanner mirror was travelling when the point was collected. The only
    /// reason we include this field is that it is in the las standard. Anyone that doesn't collect
    /// scan direction information should just keep this at the default of
    /// `ScanDirection::Unknown`, and let the las sink deal with it.
    fn scan_direction(&self) -> ScanDirection {
        ScanDirection::Unknown
    }

    /// Is this point at the edge of a flight line? Again, a crappy field that was included just
    /// becuase las.
    fn edge_of_flight_line(&self) -> bool {
        false
    }

    /// The classification of this point.
    ///
    /// I'm not sure if I want to really define out the ASPRS classification mappings in this
    /// library, or leave that to the las library. I'm leaning towards keeping that in las just
    /// because I don't like classifications as a general concept, and so I try to stay away from
    /// them whenever I can.
    ///
    /// The value of `0` is "Created, never classified" according to at least one of the las
    /// specifications, so this is a sensible default value.
    fn classification(&self) -> u8 {
        0
    }

    /// Is this a synthetic point? Urgh. las again. Just keep this false unless someone out there
    /// is actually using the synthetic field.
    fn synthetic(&self) -> bool {
        false
    }

    /// Okay, las, model key point? Really? You're taking up a perfectly good bit in *every single
    /// las point* just for this field? Really?
    fn key_point(&self) -> bool {
        false
    }

    /// It's not even worth complaining anymore. Just look at a las standard to see what all these
    /// crappy fields mean. And while you're at it, try clicking on some of the URLs *in the las
    /// standards*. I'll bet some of them are broken. That's how good ASPRS are (is?).
    fn withheld(&self) -> bool {
        false
    }

    /// Whew, back into the normal realm of fields. This is the angle of the mirror when the point
    /// was captured. Angle is usually defined with zero being straight out of the scanner.
    ///
    /// Las, in all of its wisdom, only stores these as integers, but more sensible formats allow
    /// for finer resolution, so we dial this up to `f64` and let the las sink throw away perfectly
    /// good data.
    fn scan_angle(&self) -> Option<f64> {
        None
    }

    /// Why, las, why. What is this, even.
    fn point_source_id(&self) -> Option<u16> {
        None
    }

    /// Okay, I'm done complaining now. In all seriousness, I thought about throwing this field
    /// out, in particular, but I figure since las is so used I should just mirror it. But that
    /// doesn't mean I can't whine about it.
    fn user_data(&self) -> Option<u8> {
        None
    }

    /// GNSS synchronized time.
    fn gps_time(&self) -> Option<f64> {
        None
    }

    /// The range of the point from the scanner. Note that for some formats, this explicity *does
    /// not* equal the cartesian distance to the x, y, z location of the point. This is a bit of an
    /// esoteric field but we include it because Riegl uses it a decent amount.
    fn range(&self) -> Option<f64> {
        None
    }

    /// The width of the received pulse. Again, a pretty esoteric field, this time from the Riegl
    /// side of things. I get thinking more and more how to deal with these strange fields like
    /// this.
    fn width(&self) -> Option<f64> {
        None
    }

    /// Man, this is the range index, and I have *no* idea what it means.
    fn rg_index(&self) -> Option<f64> {
        None
    }

    /// The number of the mirror facet that was used to send this pulse.
    fn facet_number(&self) -> Option<u8> {
        None
    }

    /// The target type, as an integer. Riegl uses some coded values for target type (Gaussian,
    /// Center of Gravity, etc), but at this point we don't choose to propagate those values up to
    /// this level.
    fn target_type(&self) -> Option<u8> {
        None
    }

    /// Is this point from a high channel?
    ///
    /// TODO this field should be turned into a newtype or enum
    fn high_channel(&self) -> Option<bool> {
        None
    }

    /// Converts this point into a `pabst::GenericPoint`.
    fn into_generic(self) -> GenericPoint {
        GenericPoint {
            x: self.x(),
            y: self.y(),
            z: self.z(),
            intensity: self.intensity(),
            return_number: self.return_number(),
            number_of_returns: self.number_of_returns(),
            scan_direction: self.scan_direction(),
            edge_of_flight_line: self.edge_of_flight_line(),
            classification: self.classification(),
            synthetic: self.synthetic(),
            key_point: self.key_point(),
            withheld: self.withheld(),
            scan_angle: self.scan_angle(),
            point_source_id: self.point_source_id(),
            user_data: self.user_data(),
            gps_time: self.gps_time(),
            range: self.range(),
            width: self.width(),
            rg_index: self.rg_index(),
            facet_number: self.facet_number(),
            target_type: self.target_type(),
            high_channel: self.high_channel(),
        }
    }
}

/// Implemented by structs that can be created from a `Point`.
pub trait FromPoint {
    /// Creates a new point from an object that implements `Point`.
    fn from_point<P: Point>(point: &P) -> Result<Self> where Self: Sized;
}

/// The direction that the scanner mirror was moving when the pulse was emitted.
#[derive(Clone, Copy, Debug)]
pub enum ScanDirection {
    /// Forward.
    Forward,
    /// Backwards.
    Backward,
    /// The scan direction is undefined.
    Unknown,
}

/// An intensity value, with information about its minimum and maximum possible values.
#[derive(Clone, Copy, Debug)]
pub struct Intensity {
    value: f64,
    min: f64,
    max: f64,
}

impl Intensity {
    /// Creates a new intensity with the min and the max set to the u16 bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::from_u16(10);
    /// ```
    pub fn from_u16(value: u16) -> Intensity {
        Intensity {
            value: value as f64,
            min: u16::MIN as f64,
            max: u16::MAX as f64,
        }
    }

    /// Creates a new intensity with the value, minimu, and maximum.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::new(1.0, 0.0, 2.0);
    /// assert_eq!(32767, intensity.as_u16());
    /// ```
    pub fn new(value: f64, min: f64, max: f64) -> Intensity {
        Intensity {
            value: value,
            min: min,
            max: max,
        }
    }

    /// Returns this intensity value as a u16.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::from_u16(10);
    /// assert_eq!(10, intensity.as_u16());
    /// ```
    pub fn as_u16(&self) -> u16 {
        (u16::MAX as f64 * (self.value - self.min) / (self.max - self.min)) as u16
    }
}

/// A concrete realization of a `Point`.
///
/// This can be used by intermediate processing pipelines that need to modify the fields of a
/// `Point`. Direct pass-through setups do *not* need to use generic points -- use the `FromPoint`
/// trait instead.
#[derive(Clone, Copy, Debug)]
pub struct GenericPoint {
    x: f64,
    y: f64,
    z: f64,
    intensity: Intensity,
    return_number: Option<usize>,
    number_of_returns: Option<usize>,
    scan_direction: ScanDirection,
    edge_of_flight_line: bool,
    classification: u8,
    synthetic: bool,
    key_point: bool,
    withheld: bool,
    scan_angle: Option<f64>,
    point_source_id: Option<u16>,
    user_data: Option<u8>,
    gps_time: Option<f64>,
    range: Option<f64>,
    width: Option<f64>,
    rg_index: Option<f64>,
    facet_number: Option<u8>,
    target_type: Option<u8>,
    high_channel: Option<bool>,
}

impl Point for GenericPoint {
    fn x(&self) -> f64 {
        self.x
    }
    fn y(&self) -> f64 {
        self.y
    }
    fn z(&self) -> f64 {
        self.z
    }
    fn intensity(&self) -> Intensity {
        self.intensity
    }
    fn return_number(&self) -> Option<usize> {
        self.return_number
    }
    fn number_of_returns(&self) -> Option<usize> {
        self.number_of_returns
    }
    fn scan_direction(&self) -> ScanDirection {
        self.scan_direction
    }
    fn edge_of_flight_line(&self) -> bool {
        self.edge_of_flight_line
    }
    fn classification(&self) -> u8 {
        self.classification
    }
    fn synthetic(&self) -> bool {
        self.synthetic
    }
    fn key_point(&self) -> bool {
        self.key_point
    }
    fn withheld(&self) -> bool {
        self.withheld
    }
    fn scan_angle(&self) -> Option<f64> {
        self.scan_angle
    }
    fn point_source_id(&self) -> Option<u16> {
        self.point_source_id
    }
    fn user_data(&self) -> Option<u8> {
        self.user_data
    }
    fn gps_time(&self) -> Option<f64> {
        self.gps_time
    }
    fn range(&self) -> Option<f64> {
        self.range
    }
    fn width(&self) -> Option<f64> {
        self.width
    }
    fn rg_index(&self) -> Option<f64> {
        self.rg_index
    }
    fn facet_number(&self) -> Option<u8> {
        self.facet_number
    }
    fn target_type(&self) -> Option<u8> {
        self.target_type
    }
    fn high_channel(&self) -> Option<bool> {
        self.high_channel
    }
}

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

    use las;

    use source::Source;

    #[test]
    fn generic_point() {
        let mut source = las::Stream::from_path("data/1.0_0.las").unwrap();
        let las_points = source.source(1).unwrap().unwrap();
        let points: Vec<_> = las_points.into_iter().map(|p| p.into_generic()).collect();
        assert_eq!(1, points.len());
        let ref point = points[0];
        assert_eq!(470692.44, point.x);
    }
}

<commit_msg>Make each field of GenericPoint public<commit_after>//! A trait for a LiDAR point
//!
//! This is is a catchall trait that has a bunch of optional fields. This lets sources choose what
//! values to fill in, and sinks choose what values to pay attention to.

use std::u16;

use Result;

/// A point.
pub trait Point where Self: Sized {
    /// The x dimension of a point. All points must have these.
    fn x(&self) -> f64;

    /// The y dimension of a point. All points must have these.
    fn y(&self) -> f64;

    /// The z dimension of a point. All points must have these.
    fn z(&self) -> f64;

    /// This is the intensity of the backscattered energy, as detected by the LiDAR sensor. Since
    /// each sensor has its own dynamic range, an intensity value is actually three values — the
    /// intensity value itself, the minimum possible value, and the maximum possible value.
    fn intensity(&self) -> Intensity;

    /// The return number of this point.
    fn return_number(&self) -> Option<usize>;

    /// The total number of returns in the pulse of this point.
    fn number_of_returns(&self) -> Option<usize>;

    /// The direction that the scanner mirror was travelling when the point was collected. The only
    /// reason we include this field is that it is in the las standard. Anyone that doesn't collect
    /// scan direction information should just keep this at the default of
    /// `ScanDirection::Unknown`, and let the las sink deal with it.
    fn scan_direction(&self) -> ScanDirection {
        ScanDirection::Unknown
    }

    /// Is this point at the edge of a flight line? Again, a crappy field that was included just
    /// becuase las.
    fn edge_of_flight_line(&self) -> bool {
        false
    }

    /// The classification of this point.
    ///
    /// I'm not sure if I want to really define out the ASPRS classification mappings in this
    /// library, or leave that to the las library. I'm leaning towards keeping that in las just
    /// because I don't like classifications as a general concept, and so I try to stay away from
    /// them whenever I can.
    ///
    /// The value of `0` is "Created, never classified" according to at least one of the las
    /// specifications, so this is a sensible default value.
    fn classification(&self) -> u8 {
        0
    }

    /// Is this a synthetic point? Urgh. las again. Just keep this false unless someone out there
    /// is actually using the synthetic field.
    fn synthetic(&self) -> bool {
        false
    }

    /// Okay, las, model key point? Really? You're taking up a perfectly good bit in *every single
    /// las point* just for this field? Really?
    fn key_point(&self) -> bool {
        false
    }

    /// It's not even worth complaining anymore. Just look at a las standard to see what all these
    /// crappy fields mean. And while you're at it, try clicking on some of the URLs *in the las
    /// standards*. I'll bet some of them are broken. That's how good ASPRS are (is?).
    fn withheld(&self) -> bool {
        false
    }

    /// Whew, back into the normal realm of fields. This is the angle of the mirror when the point
    /// was captured. Angle is usually defined with zero being straight out of the scanner.
    ///
    /// Las, in all of its wisdom, only stores these as integers, but more sensible formats allow
    /// for finer resolution, so we dial this up to `f64` and let the las sink throw away perfectly
    /// good data.
    fn scan_angle(&self) -> Option<f64> {
        None
    }

    /// Why, las, why. What is this, even.
    fn point_source_id(&self) -> Option<u16> {
        None
    }

    /// Okay, I'm done complaining now. In all seriousness, I thought about throwing this field
    /// out, in particular, but I figure since las is so used I should just mirror it. But that
    /// doesn't mean I can't whine about it.
    fn user_data(&self) -> Option<u8> {
        None
    }

    /// GNSS synchronized time.
    fn gps_time(&self) -> Option<f64> {
        None
    }

    /// The range of the point from the scanner. Note that for some formats, this explicity *does
    /// not* equal the cartesian distance to the x, y, z location of the point. This is a bit of an
    /// esoteric field but we include it because Riegl uses it a decent amount.
    fn range(&self) -> Option<f64> {
        None
    }

    /// The width of the received pulse. Again, a pretty esoteric field, this time from the Riegl
    /// side of things. I get thinking more and more how to deal with these strange fields like
    /// this.
    fn width(&self) -> Option<f64> {
        None
    }

    /// Man, this is the range index, and I have *no* idea what it means.
    fn rg_index(&self) -> Option<f64> {
        None
    }

    /// The number of the mirror facet that was used to send this pulse.
    fn facet_number(&self) -> Option<u8> {
        None
    }

    /// The target type, as an integer. Riegl uses some coded values for target type (Gaussian,
    /// Center of Gravity, etc), but at this point we don't choose to propagate those values up to
    /// this level.
    fn target_type(&self) -> Option<u8> {
        None
    }

    /// Is this point from a high channel?
    ///
    /// TODO this field should be turned into a newtype or enum
    fn high_channel(&self) -> Option<bool> {
        None
    }

    /// Converts this point into a `pabst::GenericPoint`.
    fn into_generic(self) -> GenericPoint {
        GenericPoint {
            x: self.x(),
            y: self.y(),
            z: self.z(),
            intensity: self.intensity(),
            return_number: self.return_number(),
            number_of_returns: self.number_of_returns(),
            scan_direction: self.scan_direction(),
            edge_of_flight_line: self.edge_of_flight_line(),
            classification: self.classification(),
            synthetic: self.synthetic(),
            key_point: self.key_point(),
            withheld: self.withheld(),
            scan_angle: self.scan_angle(),
            point_source_id: self.point_source_id(),
            user_data: self.user_data(),
            gps_time: self.gps_time(),
            range: self.range(),
            width: self.width(),
            rg_index: self.rg_index(),
            facet_number: self.facet_number(),
            target_type: self.target_type(),
            high_channel: self.high_channel(),
        }
    }
}

/// Implemented by structs that can be created from a `Point`.
pub trait FromPoint {
    /// Creates a new point from an object that implements `Point`.
    fn from_point<P: Point>(point: &P) -> Result<Self> where Self: Sized;
}

/// The direction that the scanner mirror was moving when the pulse was emitted.
#[derive(Clone, Copy, Debug)]
pub enum ScanDirection {
    /// Forward.
    Forward,
    /// Backwards.
    Backward,
    /// The scan direction is undefined.
    Unknown,
}

/// An intensity value, with information about its minimum and maximum possible values.
#[derive(Clone, Copy, Debug)]
pub struct Intensity {
    value: f64,
    min: f64,
    max: f64,
}

impl Intensity {
    /// Creates a new intensity with the min and the max set to the u16 bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::from_u16(10);
    /// ```
    pub fn from_u16(value: u16) -> Intensity {
        Intensity {
            value: value as f64,
            min: u16::MIN as f64,
            max: u16::MAX as f64,
        }
    }

    /// Creates a new intensity with the value, minimu, and maximum.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::new(1.0, 0.0, 2.0);
    /// assert_eq!(32767, intensity.as_u16());
    /// ```
    pub fn new(value: f64, min: f64, max: f64) -> Intensity {
        Intensity {
            value: value,
            min: min,
            max: max,
        }
    }

    /// Returns this intensity value as a u16.
    ///
    /// # Examples
    ///
    /// ```
    /// use pabst::point::Intensity;
    /// let intensity = Intensity::from_u16(10);
    /// assert_eq!(10, intensity.as_u16());
    /// ```
    pub fn as_u16(&self) -> u16 {
        (u16::MAX as f64 * (self.value - self.min) / (self.max - self.min)) as u16
    }
}

/// A concrete realization of a `Point`.
///
/// This can be used by intermediate processing pipelines that need to modify the fields of a
/// `Point`. Direct pass-through setups do *not* need to use generic points -- use the `FromPoint`
/// trait instead.
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub struct GenericPoint {
    pub x: f64,
    pub y: f64,
    pub z: f64,
    pub intensity: Intensity,
    pub return_number: Option<usize>,
    pub number_of_returns: Option<usize>,
    pub scan_direction: ScanDirection,
    pub edge_of_flight_line: bool,
    pub classification: u8,
    pub synthetic: bool,
    pub key_point: bool,
    pub withheld: bool,
    pub scan_angle: Option<f64>,
    pub point_source_id: Option<u16>,
    pub user_data: Option<u8>,
    pub gps_time: Option<f64>,
    pub range: Option<f64>,
    pub width: Option<f64>,
    pub rg_index: Option<f64>,
    pub facet_number: Option<u8>,
    pub target_type: Option<u8>,
    pub high_channel: Option<bool>,
}

impl Point for GenericPoint {
    fn x(&self) -> f64 {
        self.x
    }
    fn y(&self) -> f64 {
        self.y
    }
    fn z(&self) -> f64 {
        self.z
    }
    fn intensity(&self) -> Intensity {
        self.intensity
    }
    fn return_number(&self) -> Option<usize> {
        self.return_number
    }
    fn number_of_returns(&self) -> Option<usize> {
        self.number_of_returns
    }
    fn scan_direction(&self) -> ScanDirection {
        self.scan_direction
    }
    fn edge_of_flight_line(&self) -> bool {
        self.edge_of_flight_line
    }
    fn classification(&self) -> u8 {
        self.classification
    }
    fn synthetic(&self) -> bool {
        self.synthetic
    }
    fn key_point(&self) -> bool {
        self.key_point
    }
    fn withheld(&self) -> bool {
        self.withheld
    }
    fn scan_angle(&self) -> Option<f64> {
        self.scan_angle
    }
    fn point_source_id(&self) -> Option<u16> {
        self.point_source_id
    }
    fn user_data(&self) -> Option<u8> {
        self.user_data
    }
    fn gps_time(&self) -> Option<f64> {
        self.gps_time
    }
    fn range(&self) -> Option<f64> {
        self.range
    }
    fn width(&self) -> Option<f64> {
        self.width
    }
    fn rg_index(&self) -> Option<f64> {
        self.rg_index
    }
    fn facet_number(&self) -> Option<u8> {
        self.facet_number
    }
    fn target_type(&self) -> Option<u8> {
        self.target_type
    }
    fn high_channel(&self) -> Option<bool> {
        self.high_channel
    }
}

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

    use las;

    use source::Source;

    #[test]
    fn generic_point() {
        let mut source = las::Stream::from_path("data/1.0_0.las").unwrap();
        let las_points = source.source(1).unwrap().unwrap();
        let points: Vec<_> = las_points.into_iter().map(|p| p.into_generic()).collect();
        assert_eq!(1, points.len());
        let ref point = points[0];
        assert_eq!(470692.44, point.x);
    }
}

<|endoftext|>