<commit_before>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

use ast::ASTNode;
use nom::{hex_digit, digit};
use std::str;
use std_unicode;

//named!(pub parse_string< ASTNode >, map!(alt!(parse_string_literal | parse_string_short_literal), |s| ASTNode::String(s)));

//named!(parse_string_literal< ASTNode >, );

// TODO: A short literal string cannot contain unescaped line breaks nor escapes not forming a valid escape sequence.
// TODO: " ' inside strings are valid
// TODO: The escape sequence '\z' skips the following span of white-space characters, including line breaks;
// TODO: Test the newline escaping with the following newlines
// carriage return
// newline
// carriage return followed by newline
// newline followed by carriage return
named!(parse_string_short_literal<String>,
       dbg_dmp!(
       delimited!(
        alt!(tag!("\"") | tag!("'")),
        fold_many0!(alt!(
            map!(alt!(tag!("\\\r\n") | tag!("\\\n\r") | tag!("\\\n")), |_| '\n') |
            parse_byte |
            parse_unicode |
            one_of!("\x07\x08\x09\x0A\x0B\x0C\x0D")
        ), String::new(), |mut acc: String, item| {
            acc.push(item);
            acc
        }),
        alt!(tag!("\"") | tag!("'")))));

named!(parse_byte<char>, alt!(parse_byte_x | parse_byte_d));

named!(parse_byte_x<char>, map!(map_res!(map_res!(
                preceded!(tag!("\\x"), hex_digit),
                str::from_utf8),
            |s| u8::from_str_radix(s, 16)), |i: u8| i as char));

// TODO: if a decimal escape sequence is to be followed by a digit, it must be expressed using exactly three digits
// Notice, the fold_many_m_n is not actually enforcing bounds here, because digit recognizes
// more than one character, but I think this implementation might be usefull for the future
named!(parse_byte_d<char>, map!(map_res!(
            preceded!(tag!("\\"), fold_many_m_n!(1, 3, digit, String::new(), |mut acc: String, item: &[u8]| {
                for c in item {
                    acc.push(*c as char);
                }
                acc
            })),
            |s: String| s.parse::<u8>()), |i: u8| i as char));

named!(parse_unicode<char>,
       map_opt!(
           map_res!(
               map_res!(
                   delimited!(tag!("\\u{"), recognize!(hex_digit), tag!("}")),
                   str::from_utf8),
                   |h| u32::from_str_radix(h, 16)),
                   std_unicode::char::from_u32));

#[cfg(test)]
mod tests {
    ast_panic_test!(test_parse_unicode_1, parse_unicode, r#"\u{}"#);
    ast_test!(test_parse_unicode_2, parse_unicode, r#"\u{A}"#, std_unicode::char::from_u32(0xA).unwrap());
    ast_test!(test_parse_unicode_3, parse_unicode, r#"\u{a2}"#, std_unicode::char::from_u32(0xa2).unwrap());
    ast_test!(test_parse_unicode_4, parse_unicode, r#"\u{AFf9}"#, std_unicode::char::from_u32(0xAFf9).unwrap());
    ast_test!(test_parse_unicode_5, parse_unicode, r#"\u{0000000000000FFFF}"#, std_unicode::char::from_u32(0xFFFF).unwrap());
    ast_test!(test_parse_unicode_6, parse_unicode, r#"\u{10FFFF}"#, std_unicode::char::from_u32(0x10FFFF).unwrap());
    ast_panic_test!(test_parse_unicode_7, parse_unicode, r#"\u{110000}"#);

    ast_test!(test_parse_byte_d_1, parse_byte_d, r#"\0"#, '\0');
    ast_test!(test_parse_byte_d_2, parse_byte_d, r#"\00"#, '\0');
    ast_test!(test_parse_byte_d_3, parse_byte_d, r#"\000"#, '\0');
    // TODO: This should parse to the rust string r#"\u{0}0"# make this test reflect that
    ast_test!(test_parse_byte_d_4, parse_byte_d, r#"\0000"#, '\0');
    ast_test!(test_parse_byte_d_5, parse_byte_d, r#"\230"#, '\u{E6}');
    ast_panic_test!(test_parse_byte_d_6, parse_byte_d, r#"\256"#);

    ast_test!(test_parse_byte_x_1, parse_byte_x, r#"\x00"#, '\0');
    // TODO: This should parse to the rust string r#"\u{0}0"# make this test reflect that
    ast_test!(test_parse_byte_x_2, parse_byte_x, r#"\x000"#, '\0');
    ast_test!(test_parse_byte_x_3, parse_byte_x, r#"\x23"#, '\u{23}');
    ast_test!(test_parse_byte_x_4, parse_byte_x, r#"\xFf"#, '\u{FF}');

    ast_test!(test_parse_string_short_literal_1, parse_string_short_literal, r#""""#, "");
    ast_test!(test_parse_string_short_literal_2, parse_string_short_literal, r#"''"#, "");
    ast_test!(test_parse_string_short_literal_3, parse_string_short_literal, r#"'\u{1F62A}'"#, "😪");
    ast_test!(test_parse_string_short_literal_4, parse_string_short_literal, r#"'\097'"#, "a");
    ast_test!(test_parse_string_short_literal_5, parse_string_short_literal, format!("'{}'", "\x07\x08\x09\x0A\x0B\x0C\x0D"), "\x07\x08\x09\x0A\x0B\x0C\x0D");
    ast_test!(test_parse_string_short_literal_6, parse_string_short_literal, "'\\\n\r'", "\n");
    ast_test!(test_parse_string_short_literal_7, parse_string_short_literal, "'\\\r\n'", "\n");
    ast_test!(test_parse_string_short_literal_8, parse_string_short_literal, "'\\\n'", "\n");
}
<commit_msg>Add linebreak parser<commit_after>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

use ast::ASTNode;
use nom::{hex_digit, digit, sp};
use std::str;
use std_unicode;

//named!(pub parse_string< ASTNode >, map!(alt!(parse_string_literal | parse_string_short_literal), |s| ASTNode::String(s)));

//named!(parse_string_literal< ASTNode >, );

// TODO: A short literal string cannot contain unescaped line breaks nor escapes not forming a valid escape sequence.
// TODO: " ' inside strings are valid
named!(parse_string_short_literal<String>,
       dbg_dmp!(
       delimited!(
        alt!(tag!("\"") | tag!("'")),
        fold_many0!(alt!(
            map!(parse_linebreak, |_| '\n') |
            parse_byte |
            parse_unicode |
            one_of!("\x07\x08\x09\x0A\x0B\x0C\x0D")
            // Find a way to discard the output from this: preceded!(tag!(r#"\z"#), alt!(sp |
            // parse_linebreak))
        ), String::new(), |mut acc: String, item| {
            acc.push(item);
            acc
        }),
        alt!(tag!("\"") | tag!("'")))));

named!(parse_byte<char>, alt!(parse_byte_x | parse_byte_d));

named!(parse_byte_x<char>, map!(map_res!(map_res!(
                preceded!(tag!("\\x"), hex_digit),
                str::from_utf8),
            |s| u8::from_str_radix(s, 16)), |i: u8| i as char));

named!(parse_linebreak, alt!(tag!("\\\r\n") | tag!("\\\n\r") | tag!("\\\n")));

// TODO: if a decimal escape sequence is to be followed by a digit, it must be expressed using exactly three digits
// Notice, the fold_many_m_n is not actually enforcing bounds here, because digit recognizes
// more than one character, but I think this implementation might be usefull for the future
named!(parse_byte_d<char>, map!(map_res!(
            preceded!(tag!("\\"), fold_many_m_n!(1, 3, digit, String::new(), |mut acc: String, item: &[u8]| {
                for c in item {
                    acc.push(*c as char);
                }
                acc
            })),
            |s: String| s.parse::<u8>()), |i: u8| i as char));

named!(parse_unicode<char>,
       map_opt!(
           map_res!(
               map_res!(
                   delimited!(tag!("\\u{"), recognize!(hex_digit), tag!("}")),
                   str::from_utf8),
                   |h| u32::from_str_radix(h, 16)),
                   std_unicode::char::from_u32));

#[cfg(test)]
mod tests {
    ast_panic_test!(test_parse_unicode_1, parse_unicode, r#"\u{}"#);
    ast_test!(test_parse_unicode_2, parse_unicode, r#"\u{A}"#, std_unicode::char::from_u32(0xA).unwrap());
    ast_test!(test_parse_unicode_3, parse_unicode, r#"\u{a2}"#, std_unicode::char::from_u32(0xa2).unwrap());
    ast_test!(test_parse_unicode_4, parse_unicode, r#"\u{AFf9}"#, std_unicode::char::from_u32(0xAFf9).unwrap());
    ast_test!(test_parse_unicode_5, parse_unicode, r#"\u{0000000000000FFFF}"#, std_unicode::char::from_u32(0xFFFF).unwrap());
    ast_test!(test_parse_unicode_6, parse_unicode, r#"\u{10FFFF}"#, std_unicode::char::from_u32(0x10FFFF).unwrap());
    ast_panic_test!(test_parse_unicode_7, parse_unicode, r#"\u{110000}"#);

    ast_test!(test_parse_byte_d_1, parse_byte_d, r#"\0"#, '\0');
    ast_test!(test_parse_byte_d_2, parse_byte_d, r#"\00"#, '\0');
    ast_test!(test_parse_byte_d_3, parse_byte_d, r#"\000"#, '\0');
    // TODO: This should parse to the rust string r#"\u{0}0"# make this test reflect that
    ast_test!(test_parse_byte_d_4, parse_byte_d, r#"\0000"#, '\0');
    ast_test!(test_parse_byte_d_5, parse_byte_d, r#"\230"#, '\u{E6}');
    ast_panic_test!(test_parse_byte_d_6, parse_byte_d, r#"\256"#);

    ast_test!(test_parse_byte_x_1, parse_byte_x, r#"\x00"#, '\0');
    // TODO: This should parse to the rust string r#"\u{0}0"# make this test reflect that
    ast_test!(test_parse_byte_x_2, parse_byte_x, r#"\x000"#, '\0');
    ast_test!(test_parse_byte_x_3, parse_byte_x, r#"\x23"#, '\u{23}');
    ast_test!(test_parse_byte_x_4, parse_byte_x, r#"\xFf"#, '\u{FF}');

    ast_test!(test_parse_string_short_literal_1, parse_string_short_literal, r#""""#, "");
    ast_test!(test_parse_string_short_literal_2, parse_string_short_literal, r#"''"#, "");
    ast_test!(test_parse_string_short_literal_3, parse_string_short_literal, r#"'\u{1F62A}'"#, "😪");
    ast_test!(test_parse_string_short_literal_4, parse_string_short_literal, r#"'\097'"#, "a");
    ast_test!(test_parse_string_short_literal_5, parse_string_short_literal, format!("'{}'", "\x07\x08\x09\x0A\x0B\x0C\x0D"), "\x07\x08\x09\x0A\x0B\x0C\x0D");
    ast_test!(test_parse_string_short_literal_6, parse_string_short_literal, "'\\\n\r'", "\n");
    ast_test!(test_parse_string_short_literal_7, parse_string_short_literal, "'\\\r\n'", "\n");
    ast_test!(test_parse_string_short_literal_8, parse_string_short_literal, "'\\\n'", "\n");
}
<|endoftext|>


<commit_before>//! The following code generates a 1s long, 16-bit, 440Hz sinewave at a 44100Hz sample rate.
//! It then writes the generated samples into a 44100Hz WAV file at `out/sine.wav`.
//!
//! ```ignore
//! use synthrs::wave::SineWave;
//! use synthrs::writer::write_wav;
//! use synthrs::synthesizer::{quantize_samples, make_samples};
//!
//! write_wav("out/sine.wav", 44_100,
//!     quantize_samples::<i16>(make_samples(1.0, 44_100, SineWave(440.0)))
//! ).ok().expect("failed");
//! ```
//!
//! See: `examples/simple.rs`

use std::mem::size_of;
use std::iter::Iterator;

use num::Float;
use num::traits::{Bounded, FromPrimitive, Num};

use filter;
use music;
use midi;
use wave;
use errors::SynthrsError;

/// Quantizes a `f64` sample into `T`.
/// Convert from [-1.0f64, 1.0] to take up full quantization range of type `T`.
/// Behaviour is not guaranteed for `T` where `T` is unsigned.
///
/// ```
/// use synthrs::synthesizer::quantize;
///
/// assert_eq!(quantize::<i8>(1.0f64), 127i8);
/// assert_eq!(quantize::<f32>(0.0f64), 0.0f32);
/// assert_eq!(quantize::<u8>(1.0f64), 127u8); // half of available quantization space of a u8 (255)
/// assert_eq!(quantize::<u8>(-1.0f64), 129u8); // unexpected behaviour
/// ```
pub fn quantize<T>(input: f64) -> T
where
    T: Num + FromPrimitive + Bounded,
{
    let quantization_levels = 2.0.powf(size_of::<T>() as f64 * 8.0) - 1.0;
    T::from_f64(input * (quantization_levels / 2.0)).expect("failed to quantize to given type")
}

/// Quantizes a `Vec<f64>` of samples into `Vec<T>`.
///
/// This creates a 16-bit `SineWave` at 440Hz:
///
/// ```
/// use synthrs::wave::SineWave;
/// use synthrs::synthesizer::{quantize_samples, make_samples};
///
/// quantize_samples::<i16>(&make_samples(1.0, 44_100, SineWave(440.0)));
/// ```
pub fn quantize_samples<T>(input: &[f64]) -> Vec<T>
where
    T: Num + FromPrimitive + Bounded,
{
    input.iter().map(|s| quantize::<T>(*s)).collect()
}

/// Invokes the waveform function `f` at time `t` to return the amplitude at that time.
pub fn generate<F>(t: f64, f: &F) -> f64
where
    F: Fn(f64) -> f64,
{
    f.call((t,))
}

pub fn make_samples<F>(length: f64, sample_rate: usize, waveform: F) -> Vec<f64>
where
    F: Fn(f64) -> f64,
{
    let num_samples = (sample_rate as f64 * length).floor() as usize;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in 0usize..num_samples {
        let t = i as f64 / sample_rate as f64;
        samples.push(generate(t, &waveform));
    }

    samples
}

/// An iterator that generates samples of a waveform at a given sample rate
///
/// ```
/// use synthrs::synthesizer::SamplesIter;
/// use synthrs::wave::SineWave;
///
/// let mut sine_iter = SamplesIter::new(44_100, Box::new(SineWave(440.0)));
/// let samples = sine_iter.take(44_100).collect::<Vec<f64>>(); // take 1 second of samples
/// let _slice = samples.as_slice();
/// ```
pub struct SamplesIter {
    i: u64,
    sample_rate: u64,
    waveform: Box<Fn(f64) -> f64 + Send + 'static>,
}

impl SamplesIter {
    /// Returns an iterator that generates samples for the waveform at the given sample rate
    pub fn new(sample_rate: u64, waveform: Box<Fn(f64) -> f64 + Send + 'static>) -> SamplesIter {
        SamplesIter {
            i: 0,
            sample_rate: sample_rate,
            waveform: waveform,
        }
    }
}

impl Iterator for SamplesIter {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        let t = self.i as f64 / self.sample_rate as f64;
        self.i += 1;
        Some(self.waveform.call((t,)))
    }
}

/// Peak normalizes a `Vec<f64>` of samples such that the maximum and minimum amplitudes of the
/// `Vec<f64>` samples are within the range [-1.0, 1.0]
pub fn peak_normalize(samples: &[f64]) -> Vec<f64> {
    let peak = samples.iter().fold(0.0f64, |acc, &sample| {
        acc.max(sample).max(-sample)
    });

    samples.iter().map(|&sample| sample / peak).collect()
}

// This is really awful, is there a more elegant way to do this?
// TODO: Make the instrument a parameter (perhaps using an Instrument trait?)
pub fn make_samples_from_midi(sample_rate: usize, filename: &str) -> Result<Vec<f64>, SynthrsError> {
    let song = midi::read_midi(filename)?;;
    let length = (60.0 * song.max_time as f64) / (song.bpm * song.time_unit as f64);

    let mut notes_on_for_ticks: Vec<Vec<(u8, u8, usize)>> = Vec::new();
    for _ in 0..song.max_time {
        let notes_on_for_tick: Vec<(u8, u8, usize)> = Vec::new();
        notes_on_for_ticks.push(notes_on_for_tick);
    }

    for track in &song.tracks {
        for i in 0..track.events.len() {
            let event = track.events[i];
            if event.event_type == midi::EventType::NoteOn {
                let start_tick = event.time;
                let note = event.value1;
                let velocity = event.value2.unwrap_or(0);

                let mut end_tick = song.max_time;
                for j in i..track.events.len() {
                    let event_cursor = track.events[j];

                    if event_cursor.value1 == note && event_cursor.is_note_terminating() {
                        end_tick = event_cursor.time;
                        break;
                    }
                }

                for on_notes in notes_on_for_ticks.iter_mut().take(end_tick).skip(
                    start_tick,
                )
                {
                    on_notes.push((note as u8, velocity as u8, start_tick));
                }
            }
        }
    }

    let midi_frequency_function = |t: f64| -> f64 {
        let tick = (t * song.bpm * song.time_unit as f64 / 60.0) as usize;
        let mut out = 0.0;

        if tick < notes_on_for_ticks.len() {
            for &(note, velocity, start_tick) in &notes_on_for_ticks[tick] {
                let frequency = music::note_midi(440.0, note as usize);
                let loudness = (6.908 * (f64::from(velocity) / 255.0)).exp() / 1000.0;
                let attack = 0.01;
                let decay = 1.0;
                let start_t = start_tick as f64 * 60.0 / song.bpm as f64 / song.time_unit as f64;
                let relative_t = t - start_t;
                out += loudness * wave::SquareWave(frequency)(t) *
                    filter::envelope(relative_t, attack, decay)

            }
        }

        out
    };

    let num_samples = (sample_rate as f64 * length).floor() as usize;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in 0usize..num_samples {
        let t = i as f64 / sample_rate as f64;
        samples.push(midi_frequency_function(t));
    }

    Ok(peak_normalize(&samples))
}

#[cfg(test)]
mod tests {
    use std::i8;
    use std::i16;

    use super::*;
    use wave::SineWave;

    #[test]
    fn it_peak_normalizes() {
        let input_negative = vec![-2.0f64, 1.0, -1.0];
        let output_negative = peak_normalize(&input_negative);
        assert_eq!(output_negative, vec![-1.0f64, 0.5, -0.5]);

        let input_positive = vec![2.0f64, 1.0, -1.0];
        let output_positive = peak_normalize(&input_positive);
        assert_eq!(output_positive, vec![1.0f64, 0.5, -0.5])
    }

    #[test]
    fn it_quantizes() {
        assert_eq!(i8::MAX, quantize::<i8>(1.0));
        // assert_eq!(i8::MIN + 1, quantize::<i8>(-1.0)); // Bad quantization behaviour?
        assert_eq!(i16::MAX, quantize::<i16>(1.0));
        assert_eq!(0.0f32, quantize::<f32>(0.0));
        // assert_eq!(u8::MAX, quantize::<u8>(1.0)); // TODO: Make quantization work for unsigned types
    }

    #[test]
    fn test_samples_iterator() {
        let mut iter = SamplesIter::new(1, Box::new(SineWave(3.1415)));
        assert_eq!(iter.next().unwrap(), 0.0);
        assert_eq!(iter.next().unwrap(), 0.7764865126870779);
        assert_eq!(iter.next().unwrap(), 0.9785809043254725);
    }

    #[test]
    fn test_make_samples() {
        let waveform = SineWave(3.1415);
        let samples = make_samples(3.0, 1, waveform);
        assert_eq!(vec![0.0, 0.7764865126870779, 0.9785809043254725], samples);
    }
}
<commit_msg>Fix now-failing doctest from rust upgrade<commit_after>//! The following code generates a 1s long, 16-bit, 440Hz sinewave at a 44100Hz sample rate.
//! It then writes the generated samples into a 44100Hz WAV file at `out/sine.wav`.
//!
//! ```ignore
//! use synthrs::wave::SineWave;
//! use synthrs::writer::write_wav;
//! use synthrs::synthesizer::{quantize_samples, make_samples};
//!
//! write_wav("out/sine.wav", 44_100,
//!     quantize_samples::<i16>(make_samples(1.0, 44_100, SineWave(440.0)))
//! ).ok().expect("failed");
//! ```
//!
//! See: `examples/simple.rs`

use std::mem::size_of;
use std::iter::Iterator;

use num::Float;
use num::traits::{Bounded, FromPrimitive, Num};

use filter;
use music;
use midi;
use wave;
use errors::SynthrsError;

/// Quantizes a `f64` sample into `T`.
/// Convert from [-1.0f64, 1.0] to take up full quantization range of type `T`.
/// Behaviour is not guaranteed for `T` where `T` is unsigned.
///
/// ```
/// use synthrs::synthesizer::quantize;
///
/// assert_eq!(quantize::<i8>(1.0f64), 127i8);
/// assert_eq!(quantize::<f32>(0.0f64), 0.0f32);
/// assert_eq!(quantize::<u8>(1.0f64), 127u8); // half of available quantization space of a u8 (255)
/// // quantize::<u8>(-1.0f64); // panics
/// ```
pub fn quantize<T>(input: f64) -> T
where
    T: Num + FromPrimitive + Bounded,
{
    let quantization_levels = 2.0.powf(size_of::<T>() as f64 * 8.0) - 1.0;
    T::from_f64(input * (quantization_levels / 2.0)).expect("failed to quantize to given type")
}

/// Quantizes a `Vec<f64>` of samples into `Vec<T>`.
///
/// This creates a 16-bit `SineWave` at 440Hz:
///
/// ```
/// use synthrs::wave::SineWave;
/// use synthrs::synthesizer::{quantize_samples, make_samples};
///
/// quantize_samples::<i16>(&make_samples(1.0, 44_100, SineWave(440.0)));
/// ```
pub fn quantize_samples<T>(input: &[f64]) -> Vec<T>
where
    T: Num + FromPrimitive + Bounded,
{
    input.iter().map(|s| quantize::<T>(*s)).collect()
}

/// Invokes the waveform function `f` at time `t` to return the amplitude at that time.
pub fn generate<F>(t: f64, f: &F) -> f64
where
    F: Fn(f64) -> f64,
{
    f.call((t,))
}

pub fn make_samples<F>(length: f64, sample_rate: usize, waveform: F) -> Vec<f64>
where
    F: Fn(f64) -> f64,
{
    let num_samples = (sample_rate as f64 * length).floor() as usize;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in 0usize..num_samples {
        let t = i as f64 / sample_rate as f64;
        samples.push(generate(t, &waveform));
    }

    samples
}

/// An iterator that generates samples of a waveform at a given sample rate
///
/// ```
/// use synthrs::synthesizer::SamplesIter;
/// use synthrs::wave::SineWave;
///
/// let mut sine_iter = SamplesIter::new(44_100, Box::new(SineWave(440.0)));
/// let samples = sine_iter.take(44_100).collect::<Vec<f64>>(); // take 1 second of samples
/// let _slice = samples.as_slice();
/// ```
pub struct SamplesIter {
    i: u64,
    sample_rate: u64,
    waveform: Box<Fn(f64) -> f64 + Send + 'static>,
}

impl SamplesIter {
    /// Returns an iterator that generates samples for the waveform at the given sample rate
    pub fn new(sample_rate: u64, waveform: Box<Fn(f64) -> f64 + Send + 'static>) -> SamplesIter {
        SamplesIter {
            i: 0,
            sample_rate: sample_rate,
            waveform: waveform,
        }
    }
}

impl Iterator for SamplesIter {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        let t = self.i as f64 / self.sample_rate as f64;
        self.i += 1;
        Some(self.waveform.call((t,)))
    }
}

/// Peak normalizes a `Vec<f64>` of samples such that the maximum and minimum amplitudes of the
/// `Vec<f64>` samples are within the range [-1.0, 1.0]
pub fn peak_normalize(samples: &[f64]) -> Vec<f64> {
    let peak = samples.iter().fold(0.0f64, |acc, &sample| {
        acc.max(sample).max(-sample)
    });

    samples.iter().map(|&sample| sample / peak).collect()
}

// This is really awful, is there a more elegant way to do this?
// TODO: Make the instrument a parameter (perhaps using an Instrument trait?)
pub fn make_samples_from_midi(sample_rate: usize, filename: &str) -> Result<Vec<f64>, SynthrsError> {
    let song = midi::read_midi(filename)?;;
    let length = (60.0 * song.max_time as f64) / (song.bpm * song.time_unit as f64);

    let mut notes_on_for_ticks: Vec<Vec<(u8, u8, usize)>> = Vec::new();
    for _ in 0..song.max_time {
        let notes_on_for_tick: Vec<(u8, u8, usize)> = Vec::new();
        notes_on_for_ticks.push(notes_on_for_tick);
    }

    for track in &song.tracks {
        for i in 0..track.events.len() {
            let event = track.events[i];
            if event.event_type == midi::EventType::NoteOn {
                let start_tick = event.time;
                let note = event.value1;
                let velocity = event.value2.unwrap_or(0);

                let mut end_tick = song.max_time;
                for j in i..track.events.len() {
                    let event_cursor = track.events[j];

                    if event_cursor.value1 == note && event_cursor.is_note_terminating() {
                        end_tick = event_cursor.time;
                        break;
                    }
                }

                for on_notes in notes_on_for_ticks.iter_mut().take(end_tick).skip(
                    start_tick,
                )
                {
                    on_notes.push((note as u8, velocity as u8, start_tick));
                }
            }
        }
    }

    let midi_frequency_function = |t: f64| -> f64 {
        let tick = (t * song.bpm * song.time_unit as f64 / 60.0) as usize;
        let mut out = 0.0;

        if tick < notes_on_for_ticks.len() {
            for &(note, velocity, start_tick) in &notes_on_for_ticks[tick] {
                let frequency = music::note_midi(440.0, note as usize);
                let loudness = (6.908 * (f64::from(velocity) / 255.0)).exp() / 1000.0;
                let attack = 0.01;
                let decay = 1.0;
                let start_t = start_tick as f64 * 60.0 / song.bpm as f64 / song.time_unit as f64;
                let relative_t = t - start_t;
                out += loudness * wave::SquareWave(frequency)(t) *
                    filter::envelope(relative_t, attack, decay)

            }
        }

        out
    };

    let num_samples = (sample_rate as f64 * length).floor() as usize;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in 0usize..num_samples {
        let t = i as f64 / sample_rate as f64;
        samples.push(midi_frequency_function(t));
    }

    Ok(peak_normalize(&samples))
}

#[cfg(test)]
mod tests {
    use std::i8;
    use std::i16;

    use super::*;
    use wave::SineWave;

    #[test]
    fn it_peak_normalizes() {
        let input_negative = vec![-2.0f64, 1.0, -1.0];
        let output_negative = peak_normalize(&input_negative);
        assert_eq!(output_negative, vec![-1.0f64, 0.5, -0.5]);

        let input_positive = vec![2.0f64, 1.0, -1.0];
        let output_positive = peak_normalize(&input_positive);
        assert_eq!(output_positive, vec![1.0f64, 0.5, -0.5])
    }

    #[test]
    fn it_quantizes() {
        assert_eq!(i8::MAX, quantize::<i8>(1.0));
        // assert_eq!(i8::MIN + 1, quantize::<i8>(-1.0)); // Bad quantization behaviour?
        assert_eq!(i16::MAX, quantize::<i16>(1.0));
        assert_eq!(0.0f32, quantize::<f32>(0.0));
        // assert_eq!(u8::MAX, quantize::<u8>(1.0)); // TODO: Make quantization work for unsigned types
    }

    #[test]
    fn test_samples_iterator() {
        let mut iter = SamplesIter::new(1, Box::new(SineWave(3.1415)));
        assert_eq!(iter.next().unwrap(), 0.0);
        assert_eq!(iter.next().unwrap(), 0.7764865126870779);
        assert_eq!(iter.next().unwrap(), 0.9785809043254725);
    }

    #[test]
    fn test_make_samples() {
        let waveform = SineWave(3.1415);
        let samples = make_samples(3.0, 1, waveform);
        assert_eq!(vec![0.0, 0.7764865126870779, 0.9785809043254725], samples);
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use super::{EGLNativeDisplayType, EGLNativeWindowType};

pub use libc::{
   c_char, c_int, c_uint, c_void
};

pub type khronos_int32_t = c_int;

pub type EGLenum = c_uint;
pub type EGLint = khronos_int32_t;
pub type EGLBoolean = c_uint;
pub type EGLDisplay = *mut c_void;
pub type EGLConfig = *mut c_void;
pub type EGLContext = *mut c_void;
pub type EGLSurface = *mut c_void;

pub const EGL_FALSE:                        EGLenum = 0;
pub const EGL_TRUE:                         EGLenum = 1;

pub const EGL_DEFAULT_DISPLAY:              EGLNativeDisplayType = 0 as EGLNativeDisplayType;
pub const EGL_NO_CONTEXT:                   EGLContext = 0 as EGLContext;
pub const EGL_NO_DISPLAY:                   EGLDisplay = 0 as EGLDisplay;
pub const EGL_NO_SURFACE:                   EGLSurface = 0 as EGLSurface;

pub const EGL_DONT_CARE:                    EGLint = -1;

pub const EGL_SUCCESS:                      EGLenum = 0x3000;
pub const EGL_NOT_INITIALIZED:              EGLenum = 0x3001;
pub const EGL_BAD_ACCESS:                   EGLenum = 0x3002;
pub const EGL_BAD_ALLOC:                    EGLenum = 0x3003;
pub const EGL_BAD_ATTRIBUTE:                EGLenum = 0x3004;
pub const EGL_BAD_CONFIG:                   EGLenum = 0x3005;
pub const EGL_BAD_CONTEXT:                  EGLenum = 0x3006;
pub const EGL_BAD_CURRENT_SURFACE:          EGLenum = 0x3007;
pub const EGL_BAD_DISPLAY:                  EGLenum = 0x3008;
pub const EGL_BAD_MATCH:                    EGLenum = 0x3009;
pub const EGL_BAD_NATIVE_PIXMAP:            EGLenum = 0x300A;
pub const EGL_BAD_NATIVE_WINDOW:            EGLenum = 0x300B;
pub const EGL_BAD_PARAMETER:                EGLenum = 0x300C;
pub const EGL_BAD_SURFACE:                  EGLenum = 0x300D;
pub const EGL_CONTEXT_LOST:                 EGLenum = 0x300E;

pub const EGL_BUFFER_SIZE:                  EGLenum = 0x3020;
pub const EGL_ALPHA_SIZE:                   EGLenum = 0x3021;
pub const EGL_BLUE_SIZE:                    EGLenum = 0x3022;
pub const EGL_GREEN_SIZE:                   EGLenum = 0x3023;
pub const EGL_RED_SIZE:                     EGLenum = 0x3024;
pub const EGL_DEPTH_SIZE:                   EGLenum = 0x3025;
pub const EGL_STENCIL_SIZE:                 EGLenum = 0x3026;
pub const EGL_CONFIG_CAVEAT:                EGLenum = 0x3027;
pub const EGL_CONFIG_ID:                    EGLenum = 0x3028;
pub const EGL_LEVEL:                        EGLenum = 0x3029;
pub const EGL_MAX_PBUFFER_HEIGHT:           EGLenum = 0x302A;
pub const EGL_MAX_PBUFFER_PIXELS:           EGLenum = 0x302B;
pub const EGL_MAX_PBUFFER_WIDTH:            EGLenum = 0x302C;
pub const EGL_NATIVE_RENDERABLE:            EGLenum = 0x302D;
pub const EGL_NATIVE_VISUAL_ID:             EGLenum = 0x302E;
pub const EGL_NATIVE_VISUAL_TYPE:           EGLenum = 0x302F;
pub const EGL_SAMPLES:                      EGLenum = 0x3031;
pub const EGL_SAMPLE_BUFFERS:               EGLenum = 0x3032;
pub const EGL_SURFACE_TYPE:                 EGLenum = 0x3033;
pub const EGL_TRANSPARENT_TYPE:             EGLenum = 0x3034;
pub const EGL_TRANSPARENT_BLUE_VALUE:       EGLenum = 0x3035;
pub const EGL_TRANSPARENT_GREEN_VALUE:      EGLenum = 0x3036;
pub const EGL_TRANSPARENT_RED_VALUE:        EGLenum = 0x3037;
pub const EGL_NONE:                         EGLenum = 0x3038;
pub const EGL_BIND_TO_TEXTURE_RGB:          EGLenum = 0x3039;
pub const EGL_BIND_TO_TEXTURE_RGBA:         EGLenum = 0x303A;
pub const EGL_MIN_SWAP_INTERVAL:            EGLenum = 0x303B;
pub const EGL_MAX_SWAP_INTERVAL:            EGLenum = 0x303C;
pub const EGL_LUMINANCE_SIZE:               EGLenum = 0x303D;
pub const EGL_ALPHA_MASK_SIZE:              EGLenum = 0x303E;
pub const EGL_COLOR_BUFFER_TYPE:            EGLenum = 0x303F;
pub const EGL_RENDERABLE_TYPE:              EGLenum = 0x3040;
pub const EGL_MATCH_NATIVE_PIXMAP:          EGLenum = 0x3041;
pub const EGL_CONFORMANT:                   EGLenum = 0x3042;

pub const EGL_SLOW_CONFIG:                  EGLenum = 0x3050;
pub const EGL_NON_CONFORMANT_CONFIG:        EGLenum = 0x3051;
pub const EGL_TRANSPARENT_RGB:              EGLenum = 0x3052;
pub const EGL_RGB_BUFFER:                   EGLenum = 0x308E;
pub const EGL_LUMINANCE_BUFFER:             EGLenum = 0x308F;

pub const EGL_HEIGHT:                       EGLenum = 0x3056;
pub const EGL_WIDTH:                        EGLenum = 0x3057;
pub const EGL_LARGEST_PBUFFER:              EGLenum = 0x3058;
pub const EGL_TEXTURE_FORMAT:               EGLenum = 0x3080;
pub const EGL_TEXTURE_TARGET:               EGLenum = 0x3081;
pub const EGL_MIPMAP_TEXTURE:               EGLenum = 0x3082;
pub const EGL_MIPMAP_LEVEL:                 EGLenum = 0x3083;
pub const EGL_RENDER_BUFFER:                EGLenum = 0x3086;
pub const EGL_VG_COLORSPACE:                EGLenum = 0x3087;
pub const EGL_VG_ALPHA_FORMAT:              EGLenum = 0x3088;
pub const EGL_HORIZONTAL_RESOLUTION:        EGLenum = 0x3090;
pub const EGL_VERTICAL_RESOLUTION:          EGLenum = 0x3091;
pub const EGL_PIXEL_ASPECT_RATIO:           EGLenum = 0x3092;
pub const EGL_SWAP_BEHAVIOR:                EGLenum = 0x3093;
pub const EGL_MULTISAMPLE_RESOLVE:          EGLenum = 0x3099;

pub const EGL_BACK_BUFFER:                  EGLenum = 0x3084;
pub const EGL_SINGLE_BUFFER:                EGLenum = 0x3085;

pub const EGL_OPENGL_ES_API:                EGLenum = 0x30A0;
pub const EGL_OPENVG_API:                   EGLenum = 0x30A1;
pub const EGL_OPENGL_API:                   EGLenum = 0x30A2;

pub const EGL_PBUFFER_BIT:                  EGLenum = 0x0001;
pub const EGL_PIXMAP_BIT:                   EGLenum = 0x0002;
pub const EGL_WINDOW_BIT:                   EGLenum = 0x0004;
pub const EGL_VG_COLORSPACE_LINEAR_BIT:     EGLenum = 0x0020;
pub const EGL_VG_ALPHA_FORMAT_PRE_BIT:      EGLenum = 0x0040;
pub const EGL_MULTISAMPLE_RESOLVE_BOX_BIT:  EGLenum = 0x0200;
pub const EGL_SWAP_BEHAVIOR_PRESERVED_BIT:  EGLenum = 0x0400;

pub const EGL_OPENGL_ES_BIT:                EGLenum = 0x0001;
pub const EGL_OPENVG_BIT:                   EGLenum = 0x0002;
pub const EGL_OPENGL_ES2_BIT:               EGLenum = 0x0004;
pub const EGL_OPENGL_BIT:                   EGLenum = 0x0008;

pub type __eglMustCastToProperFunctionPointerType =
//   Option<extern "C" fn() -> ()>;
   *const c_void;

#[link(name="EGL")]
extern "C" {
   pub fn eglBindAPI(
      api: EGLenum
   ) -> EGLBoolean;

   pub fn eglGetDisplay(
      display_id: EGLNativeDisplayType
   ) -> EGLDisplay;

   pub fn eglInitialize(
      dpy: EGLDisplay,
      major: *mut EGLint,
      minor: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglGetConfigs(
      dpy: EGLDisplay ,
      configs: *mut EGLConfig,
      config_size: EGLint,
      num_config: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglChooseConfig(
      dpy: EGLDisplay,
      attrib_list: *const EGLint,
      configs: *mut EGLConfig,
      config_size: EGLint,
      num_config: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglGetProcAddress(
      procname: *const c_char
   ) -> __eglMustCastToProperFunctionPointerType;

   pub fn eglCreateContext(
      dpy: EGLDisplay,
      config: EGLConfig,
      share_context: EGLContext,
      attrib_list: *const EGLint
   ) -> EGLContext;

   pub fn eglCreateWindowSurface(
      dpy: EGLDisplay,
      config: EGLConfig,
      win: EGLNativeWindowType,
      attrib_list: *const EGLint
   ) -> EGLSurface;

   pub fn eglMakeCurrent(
      dpy: EGLDisplay,
      draw: EGLSurface,
      read: EGLSurface,
      ctx: EGLContext
   ) -> EGLBoolean;

   pub fn eglQueryContext(
      dpy: EGLDisplay,
      ctx: EGLContext,
      attribute: EGLint,
      value: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglSwapBuffers(
      dpy: EGLDisplay,
      surface: EGLSurface
   ) -> EGLBoolean;

   pub fn eglSwapInterval(
      dpy: EGLDisplay,
      interval: EGLint
   ) -> EGLBoolean;
}
<commit_msg>Renaming dpy to display in EGL ffi module<commit_after>#![allow(non_camel_case_types)]

use super::{EGLNativeDisplayType, EGLNativeWindowType};

pub use libc::{
   c_char, c_int, c_uint, c_void
};

pub type khronos_int32_t = c_int;

pub type EGLenum = c_uint;
pub type EGLint = khronos_int32_t;
pub type EGLBoolean = c_uint;
pub type EGLDisplay = *mut c_void;
pub type EGLConfig = *mut c_void;
pub type EGLContext = *mut c_void;
pub type EGLSurface = *mut c_void;

pub const EGL_FALSE:                        EGLenum = 0;
pub const EGL_TRUE:                         EGLenum = 1;

pub const EGL_DEFAULT_DISPLAY:              EGLNativeDisplayType = 0 as EGLNativeDisplayType;
pub const EGL_NO_CONTEXT:                   EGLContext = 0 as EGLContext;
pub const EGL_NO_DISPLAY:                   EGLDisplay = 0 as EGLDisplay;
pub const EGL_NO_SURFACE:                   EGLSurface = 0 as EGLSurface;

pub const EGL_DONT_CARE:                    EGLint = -1;

pub const EGL_SUCCESS:                      EGLenum = 0x3000;
pub const EGL_NOT_INITIALIZED:              EGLenum = 0x3001;
pub const EGL_BAD_ACCESS:                   EGLenum = 0x3002;
pub const EGL_BAD_ALLOC:                    EGLenum = 0x3003;
pub const EGL_BAD_ATTRIBUTE:                EGLenum = 0x3004;
pub const EGL_BAD_CONFIG:                   EGLenum = 0x3005;
pub const EGL_BAD_CONTEXT:                  EGLenum = 0x3006;
pub const EGL_BAD_CURRENT_SURFACE:          EGLenum = 0x3007;
pub const EGL_BAD_DISPLAY:                  EGLenum = 0x3008;
pub const EGL_BAD_MATCH:                    EGLenum = 0x3009;
pub const EGL_BAD_NATIVE_PIXMAP:            EGLenum = 0x300A;
pub const EGL_BAD_NATIVE_WINDOW:            EGLenum = 0x300B;
pub const EGL_BAD_PARAMETER:                EGLenum = 0x300C;
pub const EGL_BAD_SURFACE:                  EGLenum = 0x300D;
pub const EGL_CONTEXT_LOST:                 EGLenum = 0x300E;

pub const EGL_BUFFER_SIZE:                  EGLenum = 0x3020;
pub const EGL_ALPHA_SIZE:                   EGLenum = 0x3021;
pub const EGL_BLUE_SIZE:                    EGLenum = 0x3022;
pub const EGL_GREEN_SIZE:                   EGLenum = 0x3023;
pub const EGL_RED_SIZE:                     EGLenum = 0x3024;
pub const EGL_DEPTH_SIZE:                   EGLenum = 0x3025;
pub const EGL_STENCIL_SIZE:                 EGLenum = 0x3026;
pub const EGL_CONFIG_CAVEAT:                EGLenum = 0x3027;
pub const EGL_CONFIG_ID:                    EGLenum = 0x3028;
pub const EGL_LEVEL:                        EGLenum = 0x3029;
pub const EGL_MAX_PBUFFER_HEIGHT:           EGLenum = 0x302A;
pub const EGL_MAX_PBUFFER_PIXELS:           EGLenum = 0x302B;
pub const EGL_MAX_PBUFFER_WIDTH:            EGLenum = 0x302C;
pub const EGL_NATIVE_RENDERABLE:            EGLenum = 0x302D;
pub const EGL_NATIVE_VISUAL_ID:             EGLenum = 0x302E;
pub const EGL_NATIVE_VISUAL_TYPE:           EGLenum = 0x302F;
pub const EGL_SAMPLES:                      EGLenum = 0x3031;
pub const EGL_SAMPLE_BUFFERS:               EGLenum = 0x3032;
pub const EGL_SURFACE_TYPE:                 EGLenum = 0x3033;
pub const EGL_TRANSPARENT_TYPE:             EGLenum = 0x3034;
pub const EGL_TRANSPARENT_BLUE_VALUE:       EGLenum = 0x3035;
pub const EGL_TRANSPARENT_GREEN_VALUE:      EGLenum = 0x3036;
pub const EGL_TRANSPARENT_RED_VALUE:        EGLenum = 0x3037;
pub const EGL_NONE:                         EGLenum = 0x3038;
pub const EGL_BIND_TO_TEXTURE_RGB:          EGLenum = 0x3039;
pub const EGL_BIND_TO_TEXTURE_RGBA:         EGLenum = 0x303A;
pub const EGL_MIN_SWAP_INTERVAL:            EGLenum = 0x303B;
pub const EGL_MAX_SWAP_INTERVAL:            EGLenum = 0x303C;
pub const EGL_LUMINANCE_SIZE:               EGLenum = 0x303D;
pub const EGL_ALPHA_MASK_SIZE:              EGLenum = 0x303E;
pub const EGL_COLOR_BUFFER_TYPE:            EGLenum = 0x303F;
pub const EGL_RENDERABLE_TYPE:              EGLenum = 0x3040;
pub const EGL_MATCH_NATIVE_PIXMAP:          EGLenum = 0x3041;
pub const EGL_CONFORMANT:                   EGLenum = 0x3042;

pub const EGL_SLOW_CONFIG:                  EGLenum = 0x3050;
pub const EGL_NON_CONFORMANT_CONFIG:        EGLenum = 0x3051;
pub const EGL_TRANSPARENT_RGB:              EGLenum = 0x3052;
pub const EGL_RGB_BUFFER:                   EGLenum = 0x308E;
pub const EGL_LUMINANCE_BUFFER:             EGLenum = 0x308F;

pub const EGL_HEIGHT:                       EGLenum = 0x3056;
pub const EGL_WIDTH:                        EGLenum = 0x3057;
pub const EGL_LARGEST_PBUFFER:              EGLenum = 0x3058;
pub const EGL_TEXTURE_FORMAT:               EGLenum = 0x3080;
pub const EGL_TEXTURE_TARGET:               EGLenum = 0x3081;
pub const EGL_MIPMAP_TEXTURE:               EGLenum = 0x3082;
pub const EGL_MIPMAP_LEVEL:                 EGLenum = 0x3083;
pub const EGL_RENDER_BUFFER:                EGLenum = 0x3086;
pub const EGL_VG_COLORSPACE:                EGLenum = 0x3087;
pub const EGL_VG_ALPHA_FORMAT:              EGLenum = 0x3088;
pub const EGL_HORIZONTAL_RESOLUTION:        EGLenum = 0x3090;
pub const EGL_VERTICAL_RESOLUTION:          EGLenum = 0x3091;
pub const EGL_PIXEL_ASPECT_RATIO:           EGLenum = 0x3092;
pub const EGL_SWAP_BEHAVIOR:                EGLenum = 0x3093;
pub const EGL_MULTISAMPLE_RESOLVE:          EGLenum = 0x3099;

pub const EGL_BACK_BUFFER:                  EGLenum = 0x3084;
pub const EGL_SINGLE_BUFFER:                EGLenum = 0x3085;

pub const EGL_OPENGL_ES_API:                EGLenum = 0x30A0;
pub const EGL_OPENVG_API:                   EGLenum = 0x30A1;
pub const EGL_OPENGL_API:                   EGLenum = 0x30A2;

pub const EGL_PBUFFER_BIT:                  EGLenum = 0x0001;
pub const EGL_PIXMAP_BIT:                   EGLenum = 0x0002;
pub const EGL_WINDOW_BIT:                   EGLenum = 0x0004;
pub const EGL_VG_COLORSPACE_LINEAR_BIT:     EGLenum = 0x0020;
pub const EGL_VG_ALPHA_FORMAT_PRE_BIT:      EGLenum = 0x0040;
pub const EGL_MULTISAMPLE_RESOLVE_BOX_BIT:  EGLenum = 0x0200;
pub const EGL_SWAP_BEHAVIOR_PRESERVED_BIT:  EGLenum = 0x0400;

pub const EGL_OPENGL_ES_BIT:                EGLenum = 0x0001;
pub const EGL_OPENVG_BIT:                   EGLenum = 0x0002;
pub const EGL_OPENGL_ES2_BIT:               EGLenum = 0x0004;
pub const EGL_OPENGL_BIT:                   EGLenum = 0x0008;

pub type __eglMustCastToProperFunctionPointerType =
//   Option<extern "C" fn() -> ()>;
   *const c_void;

#[link(name="EGL")]
extern "C" {
   pub fn eglBindAPI(
      api: EGLenum
   ) -> EGLBoolean;

   pub fn eglGetDisplay(
      display_id: EGLNativeDisplayType
   ) -> EGLDisplay;

   pub fn eglInitialize(
      display: EGLDisplay,
      major: *mut EGLint,
      minor: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglGetConfigs(
      display: EGLDisplay ,
      configs: *mut EGLConfig,
      config_size: EGLint,
      num_config: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglChooseConfig(
      display: EGLDisplay,
      attrib_list: *const EGLint,
      configs: *mut EGLConfig,
      config_size: EGLint,
      num_config: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglGetProcAddress(
      procname: *const c_char
   ) -> __eglMustCastToProperFunctionPointerType;

   pub fn eglCreateContext(
      display: EGLDisplay,
      config: EGLConfig,
      share_context: EGLContext,
      attrib_list: *const EGLint
   ) -> EGLContext;

   pub fn eglCreateWindowSurface(
      display: EGLDisplay,
      config: EGLConfig,
      win: EGLNativeWindowType,
      attrib_list: *const EGLint
   ) -> EGLSurface;

   pub fn eglMakeCurrent(
      display: EGLDisplay,
      draw: EGLSurface,
      read: EGLSurface,
      ctx: EGLContext
   ) -> EGLBoolean;

   pub fn eglQueryContext(
      display: EGLDisplay,
      ctx: EGLContext,
      attribute: EGLint,
      value: *mut EGLint
   ) -> EGLBoolean;

   pub fn eglSwapBuffers(
      display: EGLDisplay,
      surface: EGLSurface
   ) -> EGLBoolean;

   pub fn eglSwapInterval(
      display: EGLDisplay,
      interval: EGLint
   ) -> EGLBoolean;
}
<|endoftext|>


<commit_before>use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};

use storage::*;
use rand;
use {Ixs, RcMut};

#[derive(Hash)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = i32;

impl TensorKind {
    pub fn add_(&mut self, rhs: &TensorKind) {
        unimplemented!()
    }
    // perform deep copy
    pub fn copy(&self) -> Self {
        unimplemented!()
    }
}

impl PartialEq for TensorKind {
    fn eq(&self, other: &TensorKind) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id == t2.id,
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id == t2.id,
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> TensorKind {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> TensorKind {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Tensor<T> {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> &'a Tensor<T> {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}
pub struct Tensor<T> {
    pub id: i32,
    value: RcMut<TensorImpl<T, Output = T>>,
}
impl<T> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
    fn new_(&self, args: D) -> T;
}

impl<T> New<usize, Tensor<T>> for Tensor<T> {
    fn new(args: usize) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> New<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(args: Vec<usize>) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn size(&self) -> Vec<usize> {
        unimplemented!()
    }
    pub fn zero_(&mut self) -> Self {
        unimplemented!()
    }
    pub fn add_(&mut self, rhs: &Tensor<T>) {
        unimplemented!()
    }
    pub fn cuda(&self) -> Self {
        unimplemented!()
    }
    pub fn cpu(&self) -> Self {
        unimplemented!()
    }
    pub fn reduce_max(&self, axis: usize) -> (Self, Tensor<i64>) {
        unimplemented!()
    }
    pub fn tensor_eq(&self, rhs: &Self) -> Tensor<i64> {
        unimplemented!()
    }
    pub fn sum(&self) -> u32 {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor {
            id: self.id,
            value: self.value.clone(),
        }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

impl Default for FloatTensor {
    fn default() -> Self {
        FloatTensor::new()
    }
}

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}
<commit_msg>add a few TensorKind stubs<commit_after>use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};

use storage::*;
use rand;
use {Ixs, RcMut};

#[derive(Hash)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = i32;

impl TensorKind {
    pub fn add_(&mut self, rhs: &TensorKind) {
        unimplemented!()
    }
    pub fn new(&self) -> Self {
        unimplemented!()
    }
    // perform deep copy
    pub fn copy(&self) -> Self {
        unimplemented!()
    }
    pub fn unsqueeze(self, dim: usize) -> Self {
        unimplemented!()
    }
    pub fn long(&self) -> Self {
        unimplemented!()
    }
    //    pub fn backend(&self) -> &
}

impl PartialEq for TensorKind {
    fn eq(&self, other: &TensorKind) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id == t2.id,
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id == t2.id,
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> TensorKind {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> TensorKind {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Tensor<T> {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> &'a Tensor<T> {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}
pub struct Tensor<T> {
    pub id: i32,
    value: RcMut<TensorImpl<T, Output = T>>,
}
impl<T> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
    fn new_(&self, args: D) -> T;
}

impl<T> New<usize, Tensor<T>> for Tensor<T> {
    fn new(args: usize) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> New<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(args: Vec<usize>) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn size(&self) -> Vec<usize> {
        unimplemented!()
    }
    pub fn zero_(&mut self) -> Self {
        unimplemented!()
    }
    pub fn add_(&mut self, rhs: &Tensor<T>) {
        unimplemented!()
    }
    pub fn cuda(&self) -> Self {
        unimplemented!()
    }
    pub fn cpu(&self) -> Self {
        unimplemented!()
    }
    pub fn reduce_max(&self, axis: usize) -> (Self, Tensor<i64>) {
        unimplemented!()
    }
    pub fn tensor_eq(&self, rhs: &Self) -> Tensor<i64> {
        unimplemented!()
    }
    pub fn sum(&self) -> u32 {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor {
            id: self.id,
            value: self.value.clone(),
        }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

impl Default for FloatTensor {
    fn default() -> Self {
        FloatTensor::new()
    }
}

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}
<|endoftext|>


<commit_before>use std::boxed::FnBox;
use std::thread::{self, spawn, JoinHandle};
use std::sync::mpsc::{channel, Sender, SendError, Receiver};
use std::sync::{Arc, Mutex};
use std::error::Error;
use std::fmt;

use queue;
use mpmc_channel;
use pubsub::{pubsub_channel, Publisher, Subscriber};

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

type Proc<'a> = Box<Runner + Send + 'a>;

#[derive(Clone)]
pub struct Thread {
    inner: ThreadInner
}

#[derive(Clone)]
struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: queue::Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: queue::Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().unwrap()
    }
}

pub struct ThreadPool {
    free_threads: Receiver<usize>, // Threads will send their id when they are free.
    thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>, // Active threads
    threads: Arc<Mutex<Vec<Thread>>>, // Threads
    max_threads: usize,
}

fn initialize(init_threads: usize, id_sender: Sender<usize>, threads: &Arc<Mutex<Vec<Thread>>>, handles: &Arc<Mutex<Vec<JoinHandle<()>>>>) {
    let mut locked_thrs = threads.lock().unwrap();
    let mut locked_handles = handles.lock().unwrap();

    for i in 0..init_threads {
        let (thr, jobs) = channel();
        let (res_sender, res_recver) = mpmc_channel(1);
        let thread = Thread::new(thr, res_recver);

        let free = id_sender.clone();
        let (sh, st) = (handles.clone(), threads.clone());

        let handle = spawn(move || {
            let sentinel = Sentinel::new(i, sh, st);
            ThreadRunner::new(i, res_sender, free, jobs).run();
            sentinel.done();
        });
        locked_handles.push(handle);
        locked_thrs.push(thread);
    }
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let threads = Arc::new(Mutex::new(Vec::new()));
        let handles = Arc::new(Mutex::new(Vec::new()));

        initialize(init_threads, sn, &threads, &handles);

        ThreadPool {
            free_threads: rc,
            thread_handles: handles,
            threads: threads,
            max_threads: max_threads
        }
    }

    pub fn thread(&self) -> Result<Thread, ThreadError> {
        let thr_id = self.free_threads.recv().expect("Could not receive free thread id");
        let thrs = self.threads.lock().unwrap();
        if thrs.len() >= self.max_threads {
            Err(ThreadError)
        } else {
            Ok(thrs[thr_id].clone())
        }
    }
}

#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    id: usize,
    thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>, // Active threads
    threads: Arc<Mutex<Vec<Thread>>>, // Thread job queues
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(
        id: usize,
        thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
        threads: Arc<Mutex<Vec<Thread>>>
        ) -> Sentinel {
        Sentinel {
            id: id,
            thread_handles: thread_handles,
            threads: threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
        }
    }
}

struct ThreadRunner {
    id: usize,
    result_chan: queue::Sender<thread::Result<()>>,
    free_chan: Sender<usize>, // ThreadRunner will send its id when it is ready to do work
    jobs: Receiver<Proc<'static>>, // Job queue
}

impl ThreadRunner {
    pub fn new(id: usize, result_chan: queue::Sender<thread::Result<()>>, free_chan: Sender<usize>, jobs: Receiver<Proc<'static>>) -> ThreadRunner {
        ThreadRunner {
            id: id,
            result_chan: result_chan,
            free_chan: free_chan,
            jobs: jobs,
        }
    }

    fn run(self) {
        self.free_chan.send(self.id).unwrap();
        loop {
            let job = self.jobs.recv().unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            self.result_chan.send(res).unwrap();
            self.free_chan.send(self.id).unwrap();
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::{channel};
    // use std::time::{Duration};
    // use std::thread::{sleep};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        thr1.start(f1);
        thr2.start(f2);
        let res = thr1.join();
        assert!(res.is_ok());

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        thr2.start(f2);
        let res = thr2.join();
        assert!(res.is_err());

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());

        thr1.start(f1);
        let res = thr1.join();
        assert!(res.is_ok());
    }
}
<commit_msg>Make spawn_thread function<commit_after>use std::boxed::FnBox;
use std::thread::{self, spawn, JoinHandle};
use std::sync::mpsc::{channel, Sender, SendError, Receiver};
use std::sync::{Arc, Mutex};
use std::error::Error;
use std::fmt;

use queue;
use mpmc_channel;

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

type Proc<'a> = Box<Runner + Send + 'a>;

#[derive(Clone)]
pub struct Thread {
    inner: ThreadInner
}

#[derive(Clone)]
struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: queue::Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: queue::Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().unwrap()
    }
}

pub struct ThreadPool {
    id_sender: Sender<usize>, // Keep this for spawning new threads.
    free_threads: Receiver<usize>, // Threads will send their id when they are free.
    thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>, // Active threads
    threads: Arc<Mutex<Vec<Thread>>>, // Threads
    max_threads: usize,
}

fn initialize(init_threads: usize, id_sender: Sender<usize>, threads: &Arc<Mutex<Vec<Thread>>>, handles: &Arc<Mutex<Vec<JoinHandle<()>>>>) {
    let mut locked_thrs = threads.lock().unwrap();
    let mut locked_handles = handles.lock().unwrap();

    for i in 0..init_threads {
        let (handle, thread) = spawn_thread(i, id_sender.clone(), threads.clone(), handles.clone());
        locked_handles.push(handle);
        locked_thrs.push(thread);
    }
}

fn spawn_thread(id: usize, free: Sender<usize>, threads: Arc<Mutex<Vec<Thread>>>, handles: Arc<Mutex<Vec<JoinHandle<()>>>>) -> (JoinHandle<()>, Thread) {
        let (thr, jobs) = channel();
        let (res_sender, res_recver) = mpmc_channel(1);
        let thread = Thread::new(thr, res_recver);

        let handle = spawn(move || {
            let sentinel = Sentinel::new(id, handles, threads);
            ThreadRunner::new(id, res_sender, free, jobs).run();
            sentinel.done();
        });

        (handle, thread)
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let threads = Arc::new(Mutex::new(Vec::new()));
        let handles = Arc::new(Mutex::new(Vec::new()));

        initialize(init_threads, sn.clone(), &threads, &handles);

        ThreadPool {
            id_sender: sn,
            free_threads: rc,
            thread_handles: handles,
            threads: threads,
            max_threads: max_threads
        }
    }

    pub fn thread(&self) -> Result<Thread, ThreadError> {
        let thr_id = self.free_threads.recv().expect("Could not receive free thread id");
        let thrs = self.threads.lock().unwrap();
        if thrs.len() >= self.max_threads {
            Err(ThreadError)
        } else {
            Ok(thrs[thr_id].clone())
        }
    }
}

#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    id: usize,
    thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>, // Active threads
    threads: Arc<Mutex<Vec<Thread>>>, // Thread job queues
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(
        id: usize,
        thread_handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
        threads: Arc<Mutex<Vec<Thread>>>
        ) -> Sentinel {
        Sentinel {
            id: id,
            thread_handles: thread_handles,
            threads: threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
        }
    }
}

struct ThreadRunner {
    id: usize,
    result_chan: queue::Sender<thread::Result<()>>,
    free_chan: Sender<usize>, // ThreadRunner will send its id when it is ready to do work
    jobs: Receiver<Proc<'static>>, // Job queue
}

impl ThreadRunner {
    pub fn new(id: usize, result_chan: queue::Sender<thread::Result<()>>, free_chan: Sender<usize>, jobs: Receiver<Proc<'static>>) -> ThreadRunner {
        ThreadRunner {
            id: id,
            result_chan: result_chan,
            free_chan: free_chan,
            jobs: jobs,
        }
    }

    fn run(self) {
        self.free_chan.send(self.id).unwrap();
        loop {
            let job = self.jobs.recv().unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            self.result_chan.send(res).unwrap();
            self.free_chan.send(self.id).unwrap();
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::{channel};
    // use std::time::{Duration};
    // use std::thread::{sleep};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        thr1.start(f1);
        thr2.start(f2);
        let res = thr1.join();
        assert!(res.is_ok());

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        thr2.start(f2);
        let res = thr2.join();
        assert!(res.is_err());

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());

        thr1.start(f1);
        let res = thr1.join();
        assert!(res.is_ok());
    }
}
<|endoftext|>


<commit_before>use std::{
    io::Write,
    net::{TcpListener, TcpStream},
};

use dicom::{
    core::{DataElement, PrimitiveValue, VR},
    dicom_value,
    dictionary_std::tags,
    object::{InMemDicomObject, StandardDataDictionary},
};
use dicom_ul::{
    pdu::reader::read_pdu,
    pdu::{
        writer::write_pdu, PDataValueType, PresentationContextProposed, PresentationContextResult,
    },
};
use structopt::StructOpt;

/// DICOM C-STORE SCP
#[derive(Debug, StructOpt)]
struct App {
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// enforce max pdu length
    #[structopt(short = "s", long = "strict")]
    strict: bool,
    /// max pdu length
    #[structopt(short = "m", long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,

    /// Which port to listen on
    #[structopt(short, default_value = "11111")]
    port: u16,
}

fn run(
    scu_stream: &mut TcpStream,
    strict: bool,
    verbose: bool,
    max_pdu_length: u32,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut buffer: Vec<u8> = Vec::with_capacity(max_pdu_length as usize);
    let mut instance_buffer: Vec<u8> = Vec::with_capacity(1024 * 1024);
    let mut pcid = 1;
    let mut msgid = 1;
    let mut sop_class_uid = "".to_string();
    let mut sop_instance_uid = "".to_string();
    loop {
        match read_pdu(scu_stream, max_pdu_length, strict) {
            Ok(mut pdu) => {
                if verbose {
                    println!("scu ----> scp: {}", pdu.short_description());
                }
                match pdu {
                    dicom_ul::Pdu::AssociationRQ {
                        protocol_version,
                        calling_ae_title,
                        called_ae_title,
                        application_context_name,
                        presentation_contexts,
                        user_variables,
                    } => {
                        buffer.clear();
                        let presentation_contexts: Vec<PresentationContextResult> =
                            presentation_contexts
                                .iter()
                                .map(|pc| {
                                    let PresentationContextProposed {
                                        id,
                                        abstract_syntax: _,
                                        transfer_syntaxes,
                                    } = &pc;
                                    PresentationContextResult {
                                    id: *id,
                                    reason:
                                        dicom_ul::pdu::PresentationContextResultReason::Acceptance,
                                    // accept the first proposed transfer syntax
                                    transfer_syntax: transfer_syntaxes[0].clone(),
                                }
                                })
                                .collect();

                        // I don't understand yet which PC ID should be returned with the C-STORE-RSP, using the first for now
                        pcid = presentation_contexts[0].id;

                        // copying most variables for now, should be set to application specific values
                        let response = dicom_ul::Pdu::AssociationAC {
                            protocol_version,
                            calling_ae_title,
                            called_ae_title,
                            application_context_name,
                            presentation_contexts,
                            user_variables,
                        };
                        write_pdu(&mut buffer, &response).unwrap();
                        if verbose {
                            println!("scu <---- scp: {}", response.short_description());
                        }
                        scu_stream.write_all(&buffer).unwrap();
                    }
                    dicom_ul::Pdu::PData { ref mut data } => {
                        if data[0].value_type == PDataValueType::Data && !data[0].is_last {
                            instance_buffer.append(&mut data[0].data);
                        } else if data[0].value_type == PDataValueType::Command && data[0].is_last {
                            // commands are always in implict VR LE
                            let ts =
                                dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased();
                            let data_value = &data[0];
                            let v = &data_value.data;

                            let obj = InMemDicomObject::read_dataset_with_ts(v.as_slice(), &ts)?;
                            msgid = obj.element(tags::MESSAGE_ID)?.to_int()?;
                            sop_class_uid = obj
                                .element(tags::AFFECTED_SOP_CLASS_UID)?
                                .to_str()?
                                .to_string();
                            sop_instance_uid = obj
                                .element(tags::AFFECTED_SOP_INSTANCE_UID)?
                                .to_str()?
                                .to_string();
                            instance_buffer.clear();
                        } else if data[0].value_type == PDataValueType::Data && data[0].is_last {
                            instance_buffer.append(&mut data[0].data);
                            use std::fs;

                            // write the files to the current directory with their SOPInstanceUID as filenames
                            fs::write(sop_instance_uid.trim_end_matches('\0'), &instance_buffer)
                                .expect("Unable to write file");

                            // send C-STORE-RSP object
                            // commands are always in implict VR LE
                            let ts =
                                dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased();

                            let obj =
                                create_cstore_response(msgid, &sop_class_uid, &sop_instance_uid);

                            let mut data = Vec::new();

                            obj.write_dataset_with_ts(&mut data, &ts)?;

                            let pdu_response = dicom_ul::Pdu::PData {
                                data: vec![dicom_ul::pdu::PDataValue {
                                    presentation_context_id: pcid,
                                    value_type: PDataValueType::Command,
                                    is_last: true,
                                    data,
                                }],
                            };
                            buffer.clear();
                            write_pdu(&mut buffer, &pdu_response).unwrap();
                            scu_stream.write_all(&buffer).unwrap();
                        }
                    }
                    dicom_ul::Pdu::ReleaseRQ => {
                        buffer.clear();
                        write_pdu(&mut buffer, &dicom_ul::Pdu::ReleaseRP).unwrap();
                        scu_stream.write_all(&buffer).unwrap();
                    }
                    _ => {}
                }
            }
            Err(dicom_ul::pdu::reader::Error::NoPduAvailable { .. }) => {
                break;
            }
            Err(_err) => {
                break;
            }
        }
    }
    Ok(())
}

fn create_cstore_response(
    message_id: u16,
    sop_class_uid: &str,
    sop_instance_uid: &str,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(
            8 + sop_class_uid.len() as i32
                + 8
                + 2
                + 8
                + 2
                + 8
                + 2
                + 8
                + 2
                + sop_instance_uid.len() as i32,
        ),
    ));

    // service
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, sop_class_uid),
    ));
    // command
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x8001]),
    ));
    // message ID being responded to
    obj.put(DataElement::new(
        tags::MESSAGE_ID_BEING_RESPONDED_TO,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));
    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0101]),
    ));
    // status https://dicom.nema.org/dicom/2013/output/chtml/part07/chapter_C.html
    obj.put(DataElement::new(
        tags::STATUS,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));
    // SOPInstanceUID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, sop_instance_uid),
    ));

    obj
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        verbose,
        strict,
        port,
        max_pdu_length,
    } = App::from_args();

    let listen_addr = format!("0.0.0.0:{}", port);
    let listener = TcpListener::bind(&listen_addr).unwrap();
    if verbose {
        println!("listening on: {}", listen_addr);
    }

    for mut stream in listener.incoming() {
        match stream {
            Ok(ref mut scu_stream) => {
                if let Err(e) = run(scu_stream, strict, verbose, max_pdu_length) {
                    eprintln!("[ERROR] {}", e);
                }
            }
            Err(e) => {
                eprintln!("[ERROR] {}", e);
            }
        }
    }

    Ok(())
}
<commit_msg>direct use of presentation context id for response<commit_after>use std::{
    io::Write,
    net::{TcpListener, TcpStream},
};

use dicom::{
    core::{DataElement, PrimitiveValue, VR},
    dicom_value,
    dictionary_std::tags,
    object::{InMemDicomObject, StandardDataDictionary},
};
use dicom_ul::{
    pdu::reader::read_pdu,
    pdu::{
        writer::write_pdu, PDataValueType, PresentationContextProposed, PresentationContextResult,
    },
};
use structopt::StructOpt;

/// DICOM C-STORE SCP
#[derive(Debug, StructOpt)]
struct App {
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// enforce max pdu length
    #[structopt(short = "s", long = "strict")]
    strict: bool,
    /// max pdu length
    #[structopt(short = "m", long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,

    /// Which port to listen on
    #[structopt(short, default_value = "11111")]
    port: u16,
}

fn run(
    scu_stream: &mut TcpStream,
    strict: bool,
    verbose: bool,
    max_pdu_length: u32,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut buffer: Vec<u8> = Vec::with_capacity(max_pdu_length as usize);
    let mut instance_buffer: Vec<u8> = Vec::with_capacity(1024 * 1024);
    let mut msgid = 1;
    let mut sop_class_uid = "".to_string();
    let mut sop_instance_uid = "".to_string();
    loop {
        match read_pdu(scu_stream, max_pdu_length, strict) {
            Ok(mut pdu) => {
                if verbose {
                    println!("scu ----> scp: {}", pdu.short_description());
                }
                match pdu {
                    dicom_ul::Pdu::AssociationRQ {
                        protocol_version,
                        calling_ae_title,
                        called_ae_title,
                        application_context_name,
                        presentation_contexts,
                        user_variables,
                    } => {
                        buffer.clear();
                        let presentation_contexts: Vec<PresentationContextResult> =
                            presentation_contexts
                                .iter()
                                .map(|pc| {
                                    let PresentationContextProposed {
                                        id,
                                        abstract_syntax: _,
                                        transfer_syntaxes,
                                    } = &pc;
                                    PresentationContextResult {
                                    id: *id,
                                    reason:
                                        dicom_ul::pdu::PresentationContextResultReason::Acceptance,
                                    // accept the first proposed transfer syntax
                                    transfer_syntax: transfer_syntaxes[0].clone(),
                                }
                                })
                                .collect();

                        // copying most variables for now, should be set to application specific values
                        let response = dicom_ul::Pdu::AssociationAC {
                            protocol_version,
                            calling_ae_title,
                            called_ae_title,
                            application_context_name,
                            presentation_contexts,
                            user_variables,
                        };
                        write_pdu(&mut buffer, &response).unwrap();
                        if verbose {
                            println!("scu <---- scp: {}", response.short_description());
                        }
                        scu_stream.write_all(&buffer).unwrap();
                    }
                    dicom_ul::Pdu::PData { ref mut data } => {
                        if data[0].value_type == PDataValueType::Data && !data[0].is_last {
                            instance_buffer.append(&mut data[0].data);
                        } else if data[0].value_type == PDataValueType::Command && data[0].is_last {
                            // commands are always in implict VR LE
                            let ts =
                                dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased();
                            let data_value = &data[0];
                            let v = &data_value.data;

                            let obj = InMemDicomObject::read_dataset_with_ts(v.as_slice(), &ts)?;
                            msgid = obj.element(tags::MESSAGE_ID)?.to_int()?;
                            sop_class_uid = obj
                                .element(tags::AFFECTED_SOP_CLASS_UID)?
                                .to_str()?
                                .to_string();
                            sop_instance_uid = obj
                                .element(tags::AFFECTED_SOP_INSTANCE_UID)?
                                .to_str()?
                                .to_string();
                            instance_buffer.clear();
                        } else if data[0].value_type == PDataValueType::Data && data[0].is_last {
                            instance_buffer.append(&mut data[0].data);
                            use std::fs;

                            // write the files to the current directory with their SOPInstanceUID as filenames
                            fs::write(sop_instance_uid.trim_end_matches('\0'), &instance_buffer)
                                .expect("Unable to write file");

                            // send C-STORE-RSP object
                            // commands are always in implict VR LE
                            let ts =
                                dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased();

                            let obj =
                                create_cstore_response(msgid, &sop_class_uid, &sop_instance_uid);

                            let mut obj_data = Vec::new();

                            obj.write_dataset_with_ts(&mut obj_data, &ts)?;

                            let pdu_response = dicom_ul::Pdu::PData {
                                data: vec![dicom_ul::pdu::PDataValue {
                                    presentation_context_id: data[0].presentation_context_id,
                                    value_type: PDataValueType::Command,
                                    is_last: true,
                                    data: obj_data,
                                }],
                            };
                            buffer.clear();
                            write_pdu(&mut buffer, &pdu_response).unwrap();
                            scu_stream.write_all(&buffer).unwrap();
                        }
                    }
                    dicom_ul::Pdu::ReleaseRQ => {
                        buffer.clear();
                        write_pdu(&mut buffer, &dicom_ul::Pdu::ReleaseRP).unwrap();
                        scu_stream.write_all(&buffer).unwrap();
                    }
                    _ => {}
                }
            }
            Err(dicom_ul::pdu::reader::Error::NoPduAvailable { .. }) => {
                break;
            }
            Err(_err) => {
                break;
            }
        }
    }
    Ok(())
}

fn create_cstore_response(
    message_id: u16,
    sop_class_uid: &str,
    sop_instance_uid: &str,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(
            8 + sop_class_uid.len() as i32
                + 8
                + 2
                + 8
                + 2
                + 8
                + 2
                + 8
                + 2
                + sop_instance_uid.len() as i32,
        ),
    ));

    // service
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, sop_class_uid),
    ));
    // command
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x8001]),
    ));
    // message ID being responded to
    obj.put(DataElement::new(
        tags::MESSAGE_ID_BEING_RESPONDED_TO,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));
    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0101]),
    ));
    // status https://dicom.nema.org/dicom/2013/output/chtml/part07/chapter_C.html
    obj.put(DataElement::new(
        tags::STATUS,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));
    // SOPInstanceUID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, sop_instance_uid),
    ));

    obj
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        verbose,
        strict,
        port,
        max_pdu_length,
    } = App::from_args();

    let listen_addr = format!("0.0.0.0:{}", port);
    let listener = TcpListener::bind(&listen_addr).unwrap();
    if verbose {
        println!("listening on: {}", listen_addr);
    }

    for mut stream in listener.incoming() {
        match stream {
            Ok(ref mut scu_stream) => {
                if let Err(e) = run(scu_stream, strict, verbose, max_pdu_length) {
                    eprintln!("[ERROR] {}", e);
                }
            }
            Err(e) => {
                eprintln!("[ERROR] {}", e);
            }
        }
    }

    Ok(())
}
<|endoftext|>