<commit_before>// Copyright © 2014, Peter Atashian

#![feature(slicing_syntax, plugin)]
#![allow(unstable)]

extern crate image;
extern crate lodepng;
#[plugin]
extern crate regex_macros;
extern crate regex;
extern crate "rustc-serialize" as serialize;

use image::{GenericImage, ImageBuffer, Pixel, Rgba, RgbaImage};
use image::ColorType::RGBA;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::io::File;
use std::io::fs::PathExtensions;
use std::num::{Float};

pub mod tilesheets;

type FloatImage = ImageBuffer<Vec<f32>, f32, Rgba<f32>>;
pub fn save(img: &RgbaImage, path: &Path) {
    image::save_buffer(path, img.as_slice(), img.width(), img.height(), RGBA(8)).unwrap();
}

pub fn read_gt_lang() -> HashMap<String, String> {
    let path = Path::new(r"work/GregTech.lang");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let reg = regex!(r"S:([\w\.]+?)=(.+?)\r?\n");
    reg.captures_iter(data.as_slice()).map(|cap|
        (cap.at(1).unwrap().to_owned(), cap.at(2).unwrap().to_owned())
    ).collect()
}
trait Srgb {
    type Linear;
    fn decode(&self) -> <Self as Srgb>::Linear;
}
impl Srgb for Rgba<u8> {
    type Linear = Rgba<f32>;
    fn decode(&self) -> Rgba<f32> {
        fn dec(x: u8) -> f32 {
            let x = x as f32 * (1. / 255.);
            if x <= 0.04045 {
                x / 12.92
            } else {
                ((x + 0.055) / (1. + 0.055)).powf(2.4)
            }
        }
        let p = Rgba([dec(self[0]), dec(self[1]), dec(self[2]), dec(self[3])]);
        Rgba([p[0] * p[3], p[1] * p[3], p[2] * p[3], p[3]])
    }
}
fn decode_srgb(img: &RgbaImage) -> FloatImage {
    let (w, h) = img.dimensions();
    ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img[(x, y)].decode()))
}
trait Linear {
    type Srgb;
    fn encode(&self) -> <Self as Linear>::Srgb;
}
impl Linear for Rgba<f32> {
    type Srgb = Rgba<u8>;
    fn encode(&self) -> Rgba<u8> {
        fn enc(x: f32) -> u8 {
            let x = if x <= 0.0031308 {
                x * 12.92
            } else {
                x.powf(1. / 2.4) * (1. + 0.055) - 0.055
            };
            (x * 255.).round().max(0.).min(255.) as u8
        }
        let p = if self[3] > 0.0001 {
            Rgba([self[0] / self[3], self[1] / self[3], self[2] / self[3], self[3]])
        } else {
            Rgba([0., 0., 0., 0.])
        };
        Rgba([enc(p[0]), enc(p[1]), enc(p[2]), enc(p[3])])
    }
}
fn encode_srgb(img: &FloatImage) -> RgbaImage {
    let (w, h) = img.dimensions();
    ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img[(x, y)].encode()))
}
fn resize(img: &FloatImage, width: u32, height: u32) -> FloatImage {
    let (w, h) = img.dimensions();
    assert!(width.cmp(&w) == height.cmp(&h));
    if width < w {
        let (rw, rh) = (w as f32 / (width as f32), h as f32 / (height as f32));
        ImageBuffer::from_fn(width, height, Box::new(|&: x: u32, y: u32| {
            let (x1, x2) = ((x as f32 * rw) as u32, ((x + 1) as f32 * rw) as u32);
            let (y1, y2) = ((y as f32 * rh) as u32, ((y + 1) as f32 * rh) as u32);
            let (mut r, mut g, mut b, mut a) = (0., 0., 0., 0.);
            for xx in range(x1, x2) {
                for yy in range(y1, y2) {
                    let p = img[(xx, yy)];
                    r += p[0];
                    g += p[1];
                    b += p[2];
                    a += p[3];
                }
            }
            let m = 1. / (((x2 - x1) * (y2 - y1)) as f32);
            Rgba([r * m, g * m, b * m, a * m])
        }))
    } else if width == w {
        img.clone()
    } else {
        let (rw, rh) = (w as f32 / (width as f32), h as f32 / (height as f32));
        ImageBuffer::from_fn(width, height, Box::new(|&: x: u32, y: u32| {
            let xx = (x as f32 * rw) as u32;
            let yy = (y as f32 * rh) as u32;
            img[(xx, yy)]
        }))
    }
}

pub fn check_lang_dups(lang: &HashMap<String, String>) {
    let mut stuff = HashMap::new();
    for (key, val) in lang.iter() {
        if key.as_slice().contains(".tooltip") { continue }
        if key.as_slice().contains("fluid.") { continue }
        if key.as_slice().contains("DESCRIPTION") { continue }
        match stuff.get(val) {
            Some(other) => {
                println!("Collision for {}", val);
                println!("{} && {}", key, other);
            },
            None => (),
        }
        stuff.insert(val.clone(), key);
    }
}
pub fn check_navbox() {
    let reg = regex!(r"(\d+) (\d+) (.+?)\r?\n");
    let path = Path::new(r"work\navbox.txt");
    let mut file = File::open(&path).unwrap();
    let navbox = file.read_to_string().unwrap();
    let navbox = navbox.as_slice();
    let path = Path::new(r"work\tilesheets\Tilesheet GT.txt");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    for cap in reg.captures_iter(data.as_slice()) {
        let name = format!("mod=GT|{}", cap.at(3).unwrap());
        let name = name.as_slice();
        if !navbox.contains(name) && !name.contains("(Fluid)") {
            println!("{}", cap.at(3).unwrap());
        }
    }
}
pub fn import_old_tilesheet(name: &str) {
    let path = Path::new(r"work/tilesheets/import.txt");
    if !path.is_file() { return }
    println!("Importing old tilesheet");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let name = format!("work/tilesheets/Tilesheet {}.txt", name);
    let path = Path::new(&name[]);
    let mut out = File::create(&path).unwrap();
    let reg = regex!(r"Edit\s+[0-9]+\s+(.+?)\s+[A-Z0-9]+\s+([0-9]+)\s+([0-9]+)\s+16px, 32px\r?\n");
    for cap in reg.captures_iter(data.as_slice()) {
        let name = cap.at(1).unwrap();
        let x = cap.at(2).unwrap();
        let y = cap.at(3).unwrap();
        (writeln!(&mut out, "{} {} {}", x, y, name)).unwrap();
    }
}
pub fn fix_lang() {
    let path = Path::new(r"work/GregTech.lang");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let data = regex!("\r").replace_all(&data[], "");
    let data = regex!("(blockores\\.[0-9]{1,3}\\.name=.*)").replace_all(&data[], "$1 (Stone)");
    let data = regex!("(blockores\\.1[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Netherrack)");
    let data = regex!("(blockores\\.2[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Endstone)");
    let data = regex!("(blockores\\.3[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Black Granite)");
    let data = regex!("(blockores\\.4[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Red Granite)");
    let data = regex!("(blockores\\.16[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Stone)");
    let data = regex!("(blockores\\.17[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Netherrack)");
    let data = regex!("(blockores\\.18[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Endstone)");
    let data = regex!("(blockores\\.19[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Black Granite)");
    let data = regex!("(blockores\\.20[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Red Granite)");
    let path = Path::new(r"work/modified.lang");
    let mut file = File::create(&path).unwrap();
    file.write_str(&data[]).unwrap();
}

fn main() {
    let args = std::os::args();
    let args = args.iter().map(|x| &x[]).collect::<Vec<_>>();
    match &args[] {
        [_, "update", name] => tilesheets::update_tilesheet(name, &[16, 32]),
        _ => println!("Invalid arguments"),
    }
}
<commit_msg>Add command to import tilesheets.<commit_after>// Copyright © 2014, Peter Atashian

#![feature(slicing_syntax, plugin)]
#![allow(unstable)]

extern crate image;
extern crate lodepng;
#[plugin]
extern crate regex_macros;
extern crate regex;
extern crate "rustc-serialize" as serialize;

use image::{GenericImage, ImageBuffer, Pixel, Rgba, RgbaImage};
use image::ColorType::RGBA;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::io::File;
use std::io::fs::PathExtensions;
use std::num::{Float};

pub mod tilesheets;

type FloatImage = ImageBuffer<Vec<f32>, f32, Rgba<f32>>;
pub fn save(img: &RgbaImage, path: &Path) {
    image::save_buffer(path, img.as_slice(), img.width(), img.height(), RGBA(8)).unwrap();
}

pub fn read_gt_lang() -> HashMap<String, String> {
    let path = Path::new(r"work/GregTech.lang");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let reg = regex!(r"S:([\w\.]+?)=(.+?)\r?\n");
    reg.captures_iter(data.as_slice()).map(|cap|
        (cap.at(1).unwrap().to_owned(), cap.at(2).unwrap().to_owned())
    ).collect()
}
trait Srgb {
    type Linear;
    fn decode(&self) -> <Self as Srgb>::Linear;
}
impl Srgb for Rgba<u8> {
    type Linear = Rgba<f32>;
    fn decode(&self) -> Rgba<f32> {
        fn dec(x: u8) -> f32 {
            let x = x as f32 * (1. / 255.);
            if x <= 0.04045 {
                x / 12.92
            } else {
                ((x + 0.055) / (1. + 0.055)).powf(2.4)
            }
        }
        let p = Rgba([dec(self[0]), dec(self[1]), dec(self[2]), dec(self[3])]);
        Rgba([p[0] * p[3], p[1] * p[3], p[2] * p[3], p[3]])
    }
}
fn decode_srgb(img: &RgbaImage) -> FloatImage {
    let (w, h) = img.dimensions();
    ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img[(x, y)].decode()))
}
trait Linear {
    type Srgb;
    fn encode(&self) -> <Self as Linear>::Srgb;
}
impl Linear for Rgba<f32> {
    type Srgb = Rgba<u8>;
    fn encode(&self) -> Rgba<u8> {
        fn enc(x: f32) -> u8 {
            let x = if x <= 0.0031308 {
                x * 12.92
            } else {
                x.powf(1. / 2.4) * (1. + 0.055) - 0.055
            };
            (x * 255.).round().max(0.).min(255.) as u8
        }
        let p = if self[3] > 0.0001 {
            Rgba([self[0] / self[3], self[1] / self[3], self[2] / self[3], self[3]])
        } else {
            Rgba([0., 0., 0., 0.])
        };
        Rgba([enc(p[0]), enc(p[1]), enc(p[2]), enc(p[3])])
    }
}
fn encode_srgb(img: &FloatImage) -> RgbaImage {
    let (w, h) = img.dimensions();
    ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img[(x, y)].encode()))
}
fn resize(img: &FloatImage, width: u32, height: u32) -> FloatImage {
    let (w, h) = img.dimensions();
    assert!(width.cmp(&w) == height.cmp(&h));
    if width < w {
        let (rw, rh) = (w as f32 / (width as f32), h as f32 / (height as f32));
        ImageBuffer::from_fn(width, height, Box::new(|&: x: u32, y: u32| {
            let (x1, x2) = ((x as f32 * rw) as u32, ((x + 1) as f32 * rw) as u32);
            let (y1, y2) = ((y as f32 * rh) as u32, ((y + 1) as f32 * rh) as u32);
            let (mut r, mut g, mut b, mut a) = (0., 0., 0., 0.);
            for xx in range(x1, x2) {
                for yy in range(y1, y2) {
                    let p = img[(xx, yy)];
                    r += p[0];
                    g += p[1];
                    b += p[2];
                    a += p[3];
                }
            }
            let m = 1. / (((x2 - x1) * (y2 - y1)) as f32);
            Rgba([r * m, g * m, b * m, a * m])
        }))
    } else if width == w {
        img.clone()
    } else {
        let (rw, rh) = (w as f32 / (width as f32), h as f32 / (height as f32));
        ImageBuffer::from_fn(width, height, Box::new(|&: x: u32, y: u32| {
            let xx = (x as f32 * rw) as u32;
            let yy = (y as f32 * rh) as u32;
            img[(xx, yy)]
        }))
    }
}

pub fn check_lang_dups(lang: &HashMap<String, String>) {
    let mut stuff = HashMap::new();
    for (key, val) in lang.iter() {
        if key.as_slice().contains(".tooltip") { continue }
        if key.as_slice().contains("fluid.") { continue }
        if key.as_slice().contains("DESCRIPTION") { continue }
        match stuff.get(val) {
            Some(other) => {
                println!("Collision for {}", val);
                println!("{} && {}", key, other);
            },
            None => (),
        }
        stuff.insert(val.clone(), key);
    }
}
pub fn check_navbox() {
    let reg = regex!(r"(\d+) (\d+) (.+?)\r?\n");
    let path = Path::new(r"work\navbox.txt");
    let mut file = File::open(&path).unwrap();
    let navbox = file.read_to_string().unwrap();
    let navbox = navbox.as_slice();
    let path = Path::new(r"work\tilesheets\Tilesheet GT.txt");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    for cap in reg.captures_iter(data.as_slice()) {
        let name = format!("mod=GT|{}", cap.at(3).unwrap());
        let name = name.as_slice();
        if !navbox.contains(name) && !name.contains("(Fluid)") {
            println!("{}", cap.at(3).unwrap());
        }
    }
}
pub fn import_old_tilesheet(name: &str) {
    let path = Path::new(r"work/tilesheets/import.txt");
    if !path.is_file() { return }
    println!("Importing old tilesheet");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let name = format!("work/tilesheets/Tilesheet {}.txt", name);
    let path = Path::new(&name[]);
    let mut out = File::create(&path).unwrap();
    let reg = regex!(r"Edit\s+[0-9]+\s+(.+?)\s+[A-Z0-9]+\s+([0-9]+)\s+([0-9]+)\s+16px, 32px\r?\n");
    for cap in reg.captures_iter(data.as_slice()) {
        let name = cap.at(1).unwrap();
        let x = cap.at(2).unwrap();
        let y = cap.at(3).unwrap();
        (writeln!(&mut out, "{} {} {}", x, y, name)).unwrap();
    }
}
pub fn fix_lang() {
    let path = Path::new(r"work/GregTech.lang");
    let mut file = File::open(&path).unwrap();
    let data = file.read_to_string().unwrap();
    let data = regex!("\r").replace_all(&data[], "");
    let data = regex!("(blockores\\.[0-9]{1,3}\\.name=.*)").replace_all(&data[], "$1 (Stone)");
    let data = regex!("(blockores\\.1[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Netherrack)");
    let data = regex!("(blockores\\.2[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Endstone)");
    let data = regex!("(blockores\\.3[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Black Granite)");
    let data = regex!("(blockores\\.4[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Red Granite)");
    let data = regex!("(blockores\\.16[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Stone)");
    let data = regex!("(blockores\\.17[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Netherrack)");
    let data = regex!("(blockores\\.18[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Endstone)");
    let data = regex!("(blockores\\.19[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Black Granite)");
    let data = regex!("(blockores\\.20[0-9]{3}\\.name=.*)").replace_all(&data[], "$1 (Red Granite)");
    let path = Path::new(r"work/modified.lang");
    let mut file = File::create(&path).unwrap();
    file.write_str(&data[]).unwrap();
}

fn main() {
    let args = std::os::args();
    let args = args.iter().map(|x| &x[]).collect::<Vec<_>>();
    match &args[] {
        [_, "update", name] => tilesheets::update_tilesheet(name, &[16, 32]),
        [_, "import", name] => import_old_tilesheet(name),
        _ => println!("Invalid arguments"),
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate portaudio;
extern crate rtlsdr;
extern crate dft;
extern crate gnuplot;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::Zero;
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;

use gnuplot::*;
use dft::{Operation, Plan};

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const SDR_BUF_SIZE: usize = 262144;

// Separating out the buffer sizes seems to help some.
const BUF_SIZE: usize = 262144;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2400000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f32 = 44100.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args().nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args().nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args().nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Initialize the PortAudio class.
    let audio = try!(pa::PortAudio::new());
    let settings =
        try!(audio.default_output_stream_settings(CHANNELS,
                                                  SAMPLE_RATE_AUDIO as f64,
                                                  BUF_SIZE as u32));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;

    // We were decimating way too much. We need to decimate in two stages: one
    // to remove nearby stations and another to match the sound card. For
    // wideband signals, 8 and 3 seems to work well and also hits that sweet
    // spot of no buffer underflows!
    //
    // TODO: need to still calculate this on the fly. In addition, we need to
    // find apporpriate decimation values for narrowband. I'm still confident
    // that the decimation value depends on the bandwitdh, but I need to
    // figure out that appropriate formula.
    //
    let dec_rate_filt = 8;
    let dec_rate_audio = 3;
    let mut sdr =
        RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

    // This holds the previous value for the moving average filter so we can
    // keep track in between iterations of reading from the SDR.
    let mut prev = Complex::new(0.0, 0.0);
    let taps = low_pass(bandwidth as f32, SAMPLE_RATE as f32, 8);

    loop {
        // Read the samples and decimate down to match the sample rate of
        // the audio that'll be going out.
        let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
        let mut iq_vec = read_samples(bytes).unwrap();
        // plot_spectrum(&iq_vec, &mut figure1);
        iq_vec = filter(iq_vec, taps.clone());
        iq_vec = decimate(iq_vec.as_slice(), dec_rate_filt);

        // After decimation, demodulate the signal and send out of the
        // thread to the receiver.
        let res = demod_fm(iq_vec, prev);
        let mut demod_iq = filter_real(res.0, taps.clone());
        demod_iq = decimate(demod_iq.as_slice(), dec_rate_audio);
        prev = res.1;

        // Get the write stream and write our samples to the stream.
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    pa::StreamAvailable::OutputUnderflowed => return Err(Box::new(pa::error::Error::OutputUnderflowed)),
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        if write_frames == 0 {
            println!("write frames is 0, are we not generating fast enough?");
        }
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = 0.005 * demod_iq[ix];
                   })?;
    }
}

fn plot_spectrum<'a>(signal: &Vec<Complex<f32>>, figure: &'a mut Figure) -> &'a mut Figure {
    let mut sig = signal.clone();
    let radix_2: u32 = (sig.len() as f32).log2().ceil() as u32;
    let new_len = 2u32.pow(radix_2) as usize;
    println!("signal len: {}, new len: {}", sig.len(), new_len);
    sig.resize(new_len, Complex::zero());
    let plan = Plan::new(Operation::Forward, new_len);
    dft::transform(&mut sig, &plan);

    // Now generate a plot.
    figure.clear_axes();
    figure.axes2d()
        .lines(0..new_len, sig.iter().map(|x| x.norm()), &[]);
    figure.show();
    figure
}

fn init_sdr(sdr_index: i32,
            fm_freq: u32,
            bandwidth: u32)
            -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_agc_mode(false));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate<T: Copy>(signal: &[T], dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1]. If we don't normalize, it seems we don't get anything.
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new((iq[0] as f32 - 127.0) / 127.0,
                                    (iq[1] as f32 - 127.0) / 127.0);
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>,
            prev: Complex<f32>)
            -> (Vec<f32>, Complex<f32>) {

    let mut p = prev.clone();
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());
    let gain = SAMPLE_RATE as f32 / (2.0 * PI * 75e3 / 8.0);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

fn filter(samples: Vec<Complex<f32>>, taps: Vec<f32>) -> Vec<Complex<f32>> {
    let mut filt_samps: Vec<Complex<f32>> = Vec::new();
    for window in samples.as_slice().windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.map(|(x, y)| x * y)
            .fold(Complex::new(0.0, 0.0), |acc, x| acc + x);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

fn filter_real(samples: Vec<f32>, taps: Vec<f32>) -> Vec<f32> {
    let mut filt_samps: Vec<f32> = Vec::new();
    for window in samples.as_slice().windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.map(|(x, y)| x * y)
            .fold(0.0, |acc, x| acc + x);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

fn low_pass(cutoff_freq: f32, sample_rate: f32, ntaps: usize) -> Vec<f32> {
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    let win_taps: Vec<f32> = hamming(ntaps);
    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                     win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}

#[inline]
fn moving_average(ntaps: usize) -> Vec<f32> {
    vec![1.0 / ntaps as f32; ntaps]
}
<commit_msg>More fiddling of settings<commit_after>extern crate num;
extern crate portaudio;
extern crate rtlsdr;
extern crate dft;
extern crate gnuplot;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::Zero;
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;

use gnuplot::*;
use dft::{Operation, Plan};

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const SDR_BUF_SIZE: usize = 262144;

// Separating out the buffer sizes seems to help some.
const BUF_SIZE: usize = 262144;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2400000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f32 = 48000.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args().nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args().nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args().nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Initialize the PortAudio class.
    let audio = try!(pa::PortAudio::new());
    let settings =
        try!(audio.default_output_stream_settings(CHANNELS,
                                                  SAMPLE_RATE_AUDIO as f64,
                                                  BUF_SIZE as u32));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;

    // We were decimating way too much. We need to decimate in two stages: one
    // to remove nearby stations and another to match the sound card. For
    // wideband signals, 8 and 3 seems to work well and also hits that sweet
    // spot of no buffer underflows!
    //
    // TODO: need to still calculate this on the fly. In addition, we need to
    // find apporpriate decimation values for narrowband. I'm still confident
    // that the decimation value depends on the bandwitdh, but I need to
    // figure out that appropriate formula.
    //
    let dec_rate_filt = 9;
    let dec_rate_audio = 3;
    let mut sdr =
        RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

    // This holds the previous value for the moving average filter so we can
    // keep track in between iterations of reading from the SDR.
    let mut prev = Complex::new(0.0, 0.0);

    // TODO: the number of taps here really affects the speed of the audio. Is
    // the filter decimating or am I just doing the filter wrong?
    let taps_filt = low_pass(bandwidth as f32, SAMPLE_RATE as f32, 8);
    let taps_audio = low_pass(bandwidth as f32 / dec_rate_filt as f32,
                              SAMPLE_RATE as f32 / dec_rate_filt as f32,
                              8);

    loop {
        // Read the samples and decimate down to match the sample rate of
        // the audio that'll be going out.
        let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
        let mut iq_vec = read_samples(bytes).unwrap();
        iq_vec = filter(iq_vec, taps_filt.clone());
        iq_vec = decimate(iq_vec.as_slice(), dec_rate_filt);

        // After decimation, demodulate the signal and send out of the
        // thread to the receiver.
        let res = demod_fm(iq_vec, prev);
        let mut demod_iq = filter_real(res.0, taps_audio.clone());
        demod_iq = decimate(demod_iq.as_slice(), dec_rate_audio);
        prev = res.1;

        // Get the write stream and write our samples to the stream.
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    pa::StreamAvailable::OutputUnderflowed =>
                        return Err(Box::new(pa::error::Error::OutputUnderflowed)),
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = 0.005 * demod_iq[ix];
                   })?;
    }
}

fn plot_spectrum<'a>(signal: &Vec<Complex<f32>>,
                     figure: &'a mut Figure)
                     -> &'a mut Figure {
    let mut sig = signal.clone();
    let radix_2: u32 = (sig.len() as f32).log2().ceil() as u32;
    let new_len = 2u32.pow(radix_2) as usize;
    println!("signal len: {}, new len: {}", sig.len(), new_len);
    sig.resize(new_len, Complex::zero());
    let plan = Plan::new(Operation::Forward, new_len);
    dft::transform(&mut sig, &plan);

    // Now generate a plot.
    figure.clear_axes();
    figure
        .axes2d()
        .lines(0..new_len, sig.iter().map(|x| x.norm()), &[]);
    figure.show();
    figure
}

fn init_sdr(sdr_index: i32,
            fm_freq: u32,
            bandwidth: u32)
            -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate<T: Copy>(signal: &[T], dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1]. If we don't normalize, it seems we don't get anything.
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new((iq[0] as f32 - 127.0) / 127.0,
                                    (iq[1] as f32 - 127.0) / 127.0);
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>,
            prev: Complex<f32>)
            -> (Vec<f32>, Complex<f32>) {

    let mut p = prev.clone();
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());
    let gain = SAMPLE_RATE as f32 / (2.0 * PI * 75e3 / 8.0);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

fn filter(samples: Vec<Complex<f32>>, taps: Vec<f32>) -> Vec<Complex<f32>> {
    let mut filt_samps: Vec<Complex<f32>> = Vec::new();
    for window in samples.as_slice().windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.map(|(x, y)| x * y)
            .fold(Complex::new(0.0, 0.0), |acc, x| acc + x);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

fn filter_real(samples: Vec<f32>, taps: Vec<f32>) -> Vec<f32> {
    let mut filt_samps: Vec<f32> = Vec::new();
    for window in samples.as_slice().windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.map(|(x, y)| x * y).fold(0.0, |acc, x| acc + x);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

fn low_pass(cutoff_freq: f32, sample_rate: f32, ntaps: usize) -> Vec<f32> {
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    let win_taps: Vec<f32> = hamming(ntaps);
    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                     win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}

#[inline]
fn moving_average(ntaps: usize) -> Vec<f32> {
    vec![1.0 / ntaps as f32; ntaps]
}
<|endoftext|>


<commit_before>#[macro_use] extern crate glium;
#[macro_use] extern crate imgui;
extern crate image;
extern crate nalgebra;
extern crate time;

use std::io::Cursor;

use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::{glutin, DisplayBuild, Surface};
use image::GenericImage;
use imgui::ImGui;
use imgui::glium_renderer::Renderer;
use nalgebra::Vec2;
use time::{SteadyTime, Duration};

#[derive(Copy, Clone)]
struct Vertex {
    in_pos: Vec2<f32>,
}

implement_vertex!(Vertex, in_pos);

impl Vertex {
    fn new(x: f32, y: f32) -> Vertex{
        Vertex { in_pos: Vec2::new(x, y) }
    }
}

struct Tunables {
    escape_threshold: f32,
    max_iteration: i32,
    speed: f32,
}

struct App {
    tunables: Tunables,
    scale: f32,
    position: Vec2<f32>,
    mouse_position: Vec2<f32>,
    mouse_down: bool,
    last_frame: Option<SteadyTime>,
    delta: Option<Duration>,
}

impl App {
    fn new() -> App {
        App {
            tunables: Tunables {
                escape_threshold: 4.0,
                max_iteration: 100,
                speed: 0.1,
            },
            scale: 1.0,
            position: Vec2::new(0.0, 0.0),
            mouse_position: Vec2::new(0.0, 0.0),
            mouse_down: false,
            last_frame: None,
            delta: None,
        }
    }

    fn frame(&mut self) {
        let now = SteadyTime::now();
        if let Some(t) = self.last_frame {
            self.delta = Some(now - t);
        }

        self.last_frame = Some(now)
    }

    fn frame_delta_seconds(&self) -> Option<f32> {
        self.delta.map(|d| d.num_nanoseconds().unwrap() as f32 / 1_000_000_000.0)
    }

    fn handle_key(&mut self, code: glutin::VirtualKeyCode) {
        let speed = self.tunables.speed;
        match code {
            glutin::VirtualKeyCode::J => self.scale *= 1.0 + speed,
            glutin::VirtualKeyCode::K => self.scale *= 1.0 - speed,
            glutin::VirtualKeyCode::W => self.position.y += speed * self.scale,
            glutin::VirtualKeyCode::S => self.position.y -= speed * self.scale,
            glutin::VirtualKeyCode::A => self.position.x -= speed * self.scale,
            glutin::VirtualKeyCode::D => self.position.x += speed * self.scale,
            _ => ()
        }
    }

    fn handle_mouse_move(&mut self, x: f32, y: f32) {
        let new_position = Vec2::new(x, y);
        if self.mouse_down {
            let diff = new_position - self.mouse_position;
            self.position = self.position - diff * self.scale;
        }

        self.mouse_position = new_position;
    }

    fn handle_mouse_click(&mut self, clicked: bool) {
        self.mouse_down = clicked
    }

    fn handle_scroll(&mut self, amount: f32) {
        let point_at = self.position + self.mouse_position * self.scale;
        let x = 0.999f32;
        self.scale *= x.powf(amount);
        self.position = point_at - self.mouse_position * self.scale;
    }
}

fn mandelbrot() {
    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 800)
        .with_depth_buffer(24)
        .with_gl_profile(glutin::GlProfile::Core)
        .build_glium().unwrap();

    let mut imgui = ImGui::init();
    imgui.set_ini_filename(None);
    let mut renderer = Renderer::init(&mut imgui, &display).unwrap();

    let shape = vec![Vertex::new(-1.0, -1.0),
                     Vertex::new(-1.0,  1.0),
                     Vertex::new( 1.0,  1.0),
                     Vertex::new(-1.0, -1.0),
                     Vertex::new( 1.0, -1.0),
                     Vertex::new( 1.0,  1.0),
                     ];

    let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let image = image::load(Cursor::new(&include_bytes!("./texture.png")[..]),
                            image::PNG).unwrap();
    let pixels: Vec<_> = image.pixels().map(|(_, _, p)| p).collect();
    let texture = glium::texture::Texture1d::new(&display, pixels).unwrap();

    let program = glium::Program::from_source(&display,
                                              &include_str!("./shaders/vertex.glsl"),
                                              &include_str!("./shaders/fragment.glsl"),
                                              None).unwrap();

    let mut app = App::new();
    loop {
        let mut target = display.draw();
        let (width, height) = target.get_dimensions();
        let mut mouse_pos = None;
        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(ElementState::Pressed, _code, Some(key_code)) => {
                    app.handle_key(key_code);
                }
                Event::MouseMoved(pos) => {
                    imgui.set_mouse_pos(pos.0 as f32, pos.1 as f32);
                    mouse_pos = Some(pos)
                }
                Event::MouseWheel(delta) => {
                    match delta {
                        glutin::MouseScrollDelta::LineDelta(_, y) |
                        glutin::MouseScrollDelta::PixelDelta(_, y) => {
                            app.handle_scroll(y)
                        }
                    }
                }
                Event::MouseInput(state, MouseButton::Left) => {
                    imgui.set_mouse_down(&[state == ElementState::Pressed,
                                           false, false, false, false]);
                    app.handle_mouse_click(state == ElementState::Pressed);
                }
                _ => ()
            }
        }
        app.frame();
        target.clear_color(0.0, 0.0, 1.0, 1.0);
        let uniforms = uniform! {
            escape_threshold: app.tunables.escape_threshold,
            max_iteration: app.tunables.max_iteration as u32,
            position: app.position,
            scale: app.scale,
            tex: &texture,
        };
        target.draw(&vertex_buffer, &indices, &program, &uniforms,
                    &Default::default()).unwrap();
        let fps = format!("FPS: {}", imgui.get_frame_rate());
        let ifps = format!("ms per frame: {}", 1000.0 / imgui.get_frame_rate());

        let ui = imgui.frame(width, height, app.frame_delta_seconds().unwrap_or(1.0 / 60.0));
        if !ui.want_capture_mouse() {
            if let Some(pos) = mouse_pos {
                app.handle_mouse_move(2.0 * (pos.0 as f32 / width as f32) - 1.0,
                                      -(2.0 * (pos.1 as f32 / height as f32) - 1.0));
            }
        }
        ui.window()
            .name(im_str!("I'm a little fractal"))
            .movable(true)
            .size((500.0, 160.0), imgui::ImGuiSetCond_FirstUseEver)
            .build(|| {
                ui.text(im_str!("w, s, a, d, drag - movement\nj, k, wheel - scale."));
                ui.text(fps.into());
                ui.text(ifps.into());
                ui.separator();
                ui.slider_i32(im_str!("Number of iterations"),
                              &mut app.tunables.max_iteration, 0, 1000).build();
                ui.slider_f32(im_str!("Escape threshold"),
                              &mut app.tunables.escape_threshold, 0.0, 10.0).build();
            });
        renderer.render(&mut target, ui).unwrap();
        target.finish().unwrap();
    }
}

fn main() {
    mandelbrot();
}
<commit_msg>tunable scroll speed<commit_after>#[macro_use] extern crate glium;
#[macro_use] extern crate imgui;
extern crate image;
extern crate nalgebra;
extern crate time;

use std::io::Cursor;

use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::{glutin, DisplayBuild, Surface};
use image::GenericImage;
use imgui::ImGui;
use imgui::glium_renderer::Renderer;
use nalgebra::Vec2;
use time::{SteadyTime, Duration};

#[derive(Copy, Clone)]
struct Vertex {
    in_pos: Vec2<f32>,
}

implement_vertex!(Vertex, in_pos);

impl Vertex {
    fn new(x: f32, y: f32) -> Vertex{
        Vertex { in_pos: Vec2::new(x, y) }
    }
}

struct Tunables {
    escape_threshold: f32,
    max_iteration: i32,
    speed: f32,
    scroll_speed: f32,
}

struct App {
    tunables: Tunables,
    scale: f32,
    position: Vec2<f32>,
    mouse_position: Vec2<f32>,
    mouse_down: bool,
    last_frame: Option<SteadyTime>,
    delta: Option<Duration>,
}

impl App {
    fn new() -> App {
        App {
            tunables: Tunables {
                escape_threshold: 4.0,
                max_iteration: 100,
                speed: 0.1,
                scroll_speed: 4.0
            },
            scale: 1.0,
            position: Vec2::new(0.0, 0.0),
            mouse_position: Vec2::new(0.0, 0.0),
            mouse_down: false,
            last_frame: None,
            delta: None,
        }
    }

    fn frame(&mut self) {
        let now = SteadyTime::now();
        if let Some(t) = self.last_frame {
            self.delta = Some(now - t);
        }

        self.last_frame = Some(now)
    }

    fn frame_delta_seconds(&self) -> Option<f32> {
        self.delta.map(|d| d.num_nanoseconds().unwrap() as f32 / 1_000_000_000.0)
    }

    fn handle_key(&mut self, code: glutin::VirtualKeyCode) {
        let speed = self.tunables.speed;
        match code {
            glutin::VirtualKeyCode::J => self.scale *= 1.0 + speed,
            glutin::VirtualKeyCode::K => self.scale *= 1.0 - speed,
            glutin::VirtualKeyCode::W => self.position.y += speed * self.scale,
            glutin::VirtualKeyCode::S => self.position.y -= speed * self.scale,
            glutin::VirtualKeyCode::A => self.position.x -= speed * self.scale,
            glutin::VirtualKeyCode::D => self.position.x += speed * self.scale,
            _ => ()
        }
    }

    fn handle_mouse_move(&mut self, x: f32, y: f32) {
        let new_position = Vec2::new(x, y);
        if self.mouse_down {
            let diff = new_position - self.mouse_position;
            self.position = self.position - diff * self.scale;
        }

        self.mouse_position = new_position;
    }

    fn handle_mouse_click(&mut self, clicked: bool) {
        self.mouse_down = clicked
    }

    fn handle_scroll(&mut self, amount: f32) {
        let point_at = self.position + self.mouse_position * self.scale;
        let x = 1.0 - 0.1f32.powf(self.tunables.scroll_speed);
        self.scale *= x.powf(amount);
        self.position = point_at - self.mouse_position * self.scale;
    }
}

fn mandelbrot() {
    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 800)
        .with_depth_buffer(24)
        .with_gl_profile(glutin::GlProfile::Core)
        .build_glium().unwrap();

    let mut imgui = ImGui::init();
    imgui.set_ini_filename(None);
    let mut renderer = Renderer::init(&mut imgui, &display).unwrap();

    let shape = vec![Vertex::new(-1.0, -1.0),
                     Vertex::new(-1.0,  1.0),
                     Vertex::new( 1.0,  1.0),
                     Vertex::new(-1.0, -1.0),
                     Vertex::new( 1.0, -1.0),
                     Vertex::new( 1.0,  1.0),
                     ];

    let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let image = image::load(Cursor::new(&include_bytes!("./texture.png")[..]),
                            image::PNG).unwrap();
    let pixels: Vec<_> = image.pixels().map(|(_, _, p)| p).collect();
    let texture = glium::texture::Texture1d::new(&display, pixels).unwrap();

    let program = glium::Program::from_source(&display,
                                              &include_str!("./shaders/vertex.glsl"),
                                              &include_str!("./shaders/fragment.glsl"),
                                              None).unwrap();

    let mut app = App::new();
    loop {
        let mut target = display.draw();
        let (width, height) = target.get_dimensions();
        let mut mouse_pos = None;
        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(ElementState::Pressed, _code, Some(key_code)) => {
                    app.handle_key(key_code);
                }
                Event::MouseMoved(pos) => {
                    imgui.set_mouse_pos(pos.0 as f32, pos.1 as f32);
                    mouse_pos = Some(pos)
                }
                Event::MouseWheel(delta) => {
                    match delta {
                        glutin::MouseScrollDelta::LineDelta(_, y) |
                        glutin::MouseScrollDelta::PixelDelta(_, y) => {
                            app.handle_scroll(y)
                        }
                    }
                }
                Event::MouseInput(state, MouseButton::Left) => {
                    imgui.set_mouse_down(&[state == ElementState::Pressed,
                                           false, false, false, false]);
                    app.handle_mouse_click(state == ElementState::Pressed);
                }
                _ => ()
            }
        }
        app.frame();
        target.clear_color(0.0, 0.0, 1.0, 1.0);
        let uniforms = uniform! {
            escape_threshold: app.tunables.escape_threshold,
            max_iteration: app.tunables.max_iteration as u32,
            position: app.position,
            scale: app.scale,
            tex: &texture,
        };
        target.draw(&vertex_buffer, &indices, &program, &uniforms,
                    &Default::default()).unwrap();
        let fps = format!("FPS: {}", imgui.get_frame_rate());
        let ifps = format!("ms per frame: {}", 1000.0 / imgui.get_frame_rate());

        let ui = imgui.frame(width, height, app.frame_delta_seconds().unwrap_or(1.0 / 60.0));
        if !ui.want_capture_mouse() {
            if let Some(pos) = mouse_pos {
                app.handle_mouse_move(2.0 * (pos.0 as f32 / width as f32) - 1.0,
                                      -(2.0 * (pos.1 as f32 / height as f32) - 1.0));
            }
        }
        ui.window()
            .name(im_str!("I'm a little fractal"))
            .movable(true)
            .size((500.0, 160.0), imgui::ImGuiSetCond_FirstUseEver)
            .build(|| {
                ui.text(im_str!("w, s, a, d, drag - movement\nj, k, wheel - scale."));
                ui.text(fps.into());
                ui.text(ifps.into());
                ui.separator();
                ui.slider_i32(im_str!("Number of iterations"),
                              &mut app.tunables.max_iteration, 0, 1000).build();
                ui.slider_f32(im_str!("Escape threshold"),
                              &mut app.tunables.escape_threshold, 0.0, 10.0).build();
                ui.slider_f32(im_str!("Scroll slowness"),
                              &mut app.tunables.scroll_speed, 0.05, 10.0).build();
            });
        renderer.render(&mut target, ui).unwrap();
        target.finish().unwrap();
    }
}

fn main() {
    mandelbrot();
}
<|endoftext|>


<commit_before>use std::cmp::PartialEq;
use std::fmt;

/// A name section of a `Mime`.
///
/// For instance, for the Mime `image/svg+xml`, it contains 3 `Name`s,
/// `image`, `svg`, and `xml`.
///
/// In all cases, `Name`s are compared case insensitive.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Name<'a> {
    /// The underlying str slice, which is _required to be lowercase_.
    /// Comparisons between two Name instances expect this, as they
    /// have to use `derive(PartialEq)` to be usable in a pattern
    source: &'a str,
}

impl<'a> Name<'a> {
    #[inline]
    pub(crate) fn new(source: &'a str) -> Self {
        Name { source }
    }

    pub(crate) const fn constant(source: &'a str) -> Self {
        Name { source }
    }

    /// Get the value of this `Name` as a string.
    ///
    /// Note that the borrow is not tied to `&self` but the `'a` lifetime, allowing the
    /// string to outlive `Name`. Alternately, there is an `impl<'a> From<Name<'a>> for &'a str`
    /// which isn't rendered by Rustdoc, that can be accessed using `str::from(name)` or `name.into()`.
    #[inline]
    pub fn as_str(&self) -> &'a str {
        self.source
    }
}

impl<'a> PartialEq<str> for Name<'a> {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        self.source.eq_ignore_ascii_case(other)
    }
}

impl<'a, 'b> PartialEq<&'b str> for Name<'a> {
    #[inline]
    fn eq(&self, other: & &'b str) -> bool {
        self == *other
    }
}

impl<'a> PartialEq<Name<'a>> for str {
    #[inline]
    fn eq(&self, other: &Name<'a>) -> bool {
        other == self
    }
}

impl<'a, 'b> PartialEq<Name<'a>> for &'b str {
    #[inline]
    fn eq(&self, other: &Name<'a>) -> bool {
        other == self
    }
}

impl<'a> AsRef<str> for Name<'a> {
    #[inline]
    fn as_ref(&self) -> &str {
        self.source
    }
}

impl<'a> From<Name<'a>> for &'a str {
    #[inline]
    fn from(name: Name<'a>) -> &'a str {
        name.source
    }
}

impl<'a> fmt::Debug for Name<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.source, f)
    }
}

impl<'a> fmt::Display for Name<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.source, f)
    }
}

// Sealed trait for `MediaType::param()`.
pub trait NameEq<'a>: PartialEq<Name<'a>> {}

impl<'a, T> NameEq<'a> for T
where
    T: PartialEq<Name<'a>>
{}

#[cfg(test)]
mod test {
    use std::str::FromStr;
    use super::Name;
    use super::super::MediaType;

    #[test]
    fn test_name_eq_str() {
        let param = Name { source: "ABC" };

        assert_eq!(param, param);
        assert_eq!(param, "ABC");
        assert_eq!("ABC", param);
        assert_eq!(param, "abc");
        assert_eq!("abc", param);
    }

    #[test]
    fn test_name_eq_name() {
        let mime1 = MediaType::from_str(r#"text/x-custom; abc=a"#).unwrap();
        let mime2 = MediaType::from_str(r#"text/x-custom; aBc=a"#).unwrap();
        let param1 = mime1.params().next().unwrap().0;
        let param2 = mime2.params().next().unwrap().0;

        assert_eq!(param1, param2);
    }
}
<commit_msg>properly seal NameEq trait<commit_after>use std::cmp::PartialEq;
use std::fmt;

/// A name section of a `Mime`.
///
/// For instance, for the Mime `image/svg+xml`, it contains 3 `Name`s,
/// `image`, `svg`, and `xml`.
///
/// In all cases, `Name`s are compared case insensitive.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Name<'a> {
    /// The underlying str slice, which is _required to be lowercase_.
    /// Comparisons between two Name instances expect this, as they
    /// have to use `derive(PartialEq)` to be usable in a pattern
    source: &'a str,
}

impl<'a> Name<'a> {
    #[inline]
    pub(crate) fn new(source: &'a str) -> Self {
        Name { source }
    }

    pub(crate) const fn constant(source: &'a str) -> Self {
        Name { source }
    }

    /// Get the value of this `Name` as a string.
    ///
    /// Note that the borrow is not tied to `&self` but the `'a` lifetime, allowing the
    /// string to outlive `Name`. Alternately, there is an `impl<'a> From<Name<'a>> for &'a str`
    /// which isn't rendered by Rustdoc, that can be accessed using `str::from(name)` or `name.into()`.
    #[inline]
    pub fn as_str(&self) -> &'a str {
        self.source
    }
}

impl<'a> PartialEq<str> for Name<'a> {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        self.source.eq_ignore_ascii_case(other)
    }
}

impl<'a, 'b> PartialEq<&'b str> for Name<'a> {
    #[inline]
    fn eq(&self, other: & &'b str) -> bool {
        self == *other
    }
}

impl<'a> PartialEq<Name<'a>> for str {
    #[inline]
    fn eq(&self, other: &Name<'a>) -> bool {
        other == self
    }
}

impl<'a, 'b> PartialEq<Name<'a>> for &'b str {
    #[inline]
    fn eq(&self, other: &Name<'a>) -> bool {
        other == self
    }
}

impl<'a> AsRef<str> for Name<'a> {
    #[inline]
    fn as_ref(&self) -> &str {
        self.source
    }
}

impl<'a> From<Name<'a>> for &'a str {
    #[inline]
    fn from(name: Name<'a>) -> &'a str {
        name.source
    }
}

impl<'a> fmt::Debug for Name<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.source, f)
    }
}

impl<'a> fmt::Display for Name<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.source, f)
    }
}

// Sealed trait for `MediaType::param()`.
pub trait NameEq<'a>: PartialEq<Name<'a>> + Sealed {}

pub trait Sealed {}

impl<'a> Sealed for Name<'a> {}
impl<'a> Sealed for &'a str {}

impl<'a, T> NameEq<'a> for T
where
    T: PartialEq<Name<'a>> + Sealed,
{}

#[cfg(test)]
mod test {
    use std::str::FromStr;
    use super::Name;
    use super::super::MediaType;

    #[test]
    fn test_name_eq_str() {
        let param = Name { source: "ABC" };

        assert_eq!(param, param);
        assert_eq!(param, "ABC");
        assert_eq!("ABC", param);
        assert_eq!(param, "abc");
        assert_eq!("abc", param);
    }

    #[test]
    fn test_name_eq_name() {
        let mime1 = MediaType::from_str(r#"text/x-custom; abc=a"#).unwrap();
        let mime2 = MediaType::from_str(r#"text/x-custom; aBc=a"#).unwrap();
        let param1 = mime1.params().next().unwrap().0;
        let param2 = mime2.params().next().unwrap().0;

        assert_eq!(param1, param2);
    }
}
<|endoftext|>


<commit_before>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut, From};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::fmt::{Debug, Formatter};

use super::{BezCurve, lerp};

/// A struct that contains range information for slicing, used for slicing into the global factor
/// vector. The reason this is used instead of stdlib's `Range` struct is that `Range` does not
/// implement Copy, which means we have to use `RefCell`s instead of `Cell`s for interior mutability.
#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: u64, k: u64) -> u64 {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(mut n: u64) -> u64 {
    let mut accumulator: u64 = 1;
    while n > 0 {
        accumulator = accumulator.checked_mul(n).expect("Attempted to create Bézier curve with combination that overflow u64; decrease curve order");
        n -= 1;
    }
    accumulator
}

/// Gets the index of the bezier factors inside of FACTORS global.
fn order_index(order: usize) -> usize {
    (order*order+order)/2
}

thread_local!{
    static FACTORS: RefCell<(isize, Vec<u64>)> = RefCell::new((-1, Vec::with_capacity(order_index(20+1))))
}

/// Returns a RangeSlice for FACTORS with the appropriate factors for the given order. Calculates
/// factors if necessary.
fn factors(order: usize) -> RangeSlice {
    FACTORS.with(|f| {
        let max_order = f.borrow().0;
        if order as isize > max_order {
            let mut f = f.borrow_mut();
            f.0 = order as isize;

            // Because max_order defines the maximum current order, we need to increment it in order to avoid
            // re-pushing the current max order. Also, we increment the upper bound, `order`, so that the
            // calculations include `order`.
            for n in (max_order+1) as usize..order+1 {
                for k in 0..n+1 {
                    f.1.push(combination(n as u64, k as u64));
                }
            }
        }

        let order_index = order_index(order);
        RangeSlice::new(order_index, order_index+order+1)
    })
}

/// An n-order bezier polynomial
#[derive(Clone)]
pub struct NBezPoly<F, C = Vec<F>>
        where F: Float,
              C: AsRef<[F]> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<F>
}

impl<F, C> From<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn from(container: C) -> NBezPoly<F, C> {
        NBezPoly::from_container(container)
    }
}

impl<F, C> NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    #[inline]
    pub fn from_container(points: C) -> NBezPoly<F, C> {
        if points.as_ref().len() >= 22 {
            panic!("Cannot create Bézier polynomials with an order >= 21")
        }

        NBezPoly {
            points: points,
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }

    unsafe fn interp_unchecked<I: Iterator<Item=F>>(t: F, factors: RangeSlice, iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = factors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            point *
                            F::from_u64(fs.1[factors.start + factor]).unwrap();
                factor += 1;
            }
        });
        acc
    }

    unsafe fn slope_unchecked<I: Iterator<Item=F>>(t: F, dfactors: RangeSlice, mut iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = dfactors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;
        let mut point_next = iter.next().unwrap();

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            (point - point_next) *
                            F::from_u64(fs.1[dfactors.start + factor] * (order + 1) as u64).unwrap();
                point_next = point;
                factor += 1;
            }
        });
        acc
    }
}

impl<F, C> BezCurve<F> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    type Point = F;
    type Vector = F;
    type Elevated = NBezPoly<F>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[F]) -> Option<NBezPoly<F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        if self.factors.get().len() != self.order() + 1 {
            self.factors.set(factors(self.order()))
        }

        unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, self.factors.get(), points.iter().map(|f| *f)) }
    }

    fn slope_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        let order = self.order() - 1;
        if self.dfactors.get().len() != order + 1 {
            self.dfactors.set(factors(order))
        }

        unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, self.dfactors.get(), points.iter().map(|f| *f)) }
    }

    fn elevate(&self) -> NBezPoly<F> {
        let points = self.points.as_ref();
        let order = self.order() + 1;
        let order_f = F::from_usize(order).unwrap();

        // Elevated points
        let mut el_points = Vec::with_capacity(order + 1);
        el_points.push(points[0]);

        let mut prev_p = points[0];
        for (i, p) in points.iter().map(|p| *p).enumerate().skip(1) {
            el_points.push(lerp(p, prev_p, F::from_usize(i).unwrap()/order_f));

            prev_p = p;
        }

        el_points.push(points[self.order()]);
        NBezPoly::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBezPoly<F, C>, NBezPoly<F, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }
}

impl<F, C> AsRef<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C> AsMut<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<F, C> Debug for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBezPoly")
            .field(&self.points)
            .finish()
    }
}

#[derive(Clone)]
pub struct NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,

    phantom: PhantomData<(F, P, V)>
}

impl<P, V, F, C> From<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn from(container: C) -> NBez<P, V, F, C> {
        NBez::from_container(container)
    }
}

impl<P, V, F, C> NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    /// Create a new `NBez` curve from a container
    pub fn from_container(container: C) -> NBez<P, V, F, C> {
        if container.as_ref().len() >= 22 {
            panic!("Cannot create Bézier curves with an order >= 21")
        }

        NBez {
            points: container,
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),

            phantom: PhantomData,
        }
    }

    /// Get the wrapped container, destroying the `NBez` curve
    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<P, V, F, C> BezCurve<F> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    type Point = P;
    type Vector = V;
    type Elevated = NBez<P, V, F, Vec<P>>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[P]) -> Option<NBez<P, V, F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();

        // Initialize a point by cloning one from the point list
        let mut point = points[0].clone();

        // If the factors aren't correct for the current order, recompute factors
        if self.factors.get().len() != self.order() + 1 {
            self.factors.set(factors(self.order()))
        }

        // Iterate over all elements of the point and set them to the interpolated value
        for (i, f) in point.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, self.factors.get(), iter) };
        }

        point
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();

        // Initialize a vector by cloning it from the point list and converting it into a vector
        let mut vector: V = points[0].clone().into();
        let order = self.order() - 1;

        if self.dfactors.get().len() != order + 1{
            self.dfactors.set(factors(order))
        }

        // Iterate over all elements of the vector and set them to the interpolated value
        for (i, f) in vector.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, self.dfactors.get(), iter) };
        }

        vector
    }

    fn elevate(&self) -> NBez<P, V, F, Vec<P>> {
        let points = self.points.as_ref();
        let order = F::from_usize(self.order() + 1).unwrap();

        let mut el_points = Vec::with_capacity(points.len() + 1);
        el_points.push(points[0].clone());

        let mut prev_p = points[0].clone();
        for (i, p) in points.iter().enumerate().skip(1) {
            // Push an arbitrary point onto the vector for modification
            el_points.push(p.clone());

            // Iterate over each dimension of the current (c) and previous (r) point and interpolate
            // between them
            for (d, (c, r)) in p.as_ref().iter().zip(prev_p.as_ref().iter()).map(|(c, r)| (*c, *r)).enumerate() {
                el_points[i].as_mut()[d] = lerp(c, r, F::from_usize(i).unwrap()/order);
            }
            prev_p = p.clone();
        }
        el_points.push(points[points.len()-1].clone());
        NBez::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBez<P, V, F, C>, NBez<P, V, F, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len() - 1
    }
}

impl<P, V, F, C> AsRef<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<P, V, F, C> AsMut<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<P, V, F, C> Debug for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]> + Debug,
              P: Point<F>,
              V: Vector<F, P> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBez")
            .field(&self.points)
            .finish()
    }
}<commit_msg>Update NBez and NBezPoly to contain factors in local `Vec`s<commit_after>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut, From};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::fmt::{Debug, Formatter};
use std::ops::Range;

use super::{BezCurve, lerp};

/// A struct that contains range information for slicing, used for slicing into the global factor
/// vector. The reason this is used instead of stdlib's `Range` struct is that `Range` does not
/// implement Copy, which means we have to use `RefCell`s instead of `Cell`s for interior mutability.
#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn as_range(&self) -> Range<usize> {
        self.start..self.end
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: u64, k: u64) -> u64 {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(mut n: u64) -> u64 {
    let mut accumulator: u64 = 1;
    while n > 0 {
        accumulator = accumulator.checked_mul(n).expect("Attempted to create Bézier curve with combination that overflow u64; decrease curve order");
        n -= 1;
    }
    accumulator
}

/// Given the `order` and references to the `factors`, `dfactors`, and `vec` cells, update the
/// cells to contain accurate information about the factors of the order.
fn update_factors(order: usize, factors: &Cell<RangeSlice>, dfactors: &Cell<RangeSlice>, vec: &RefCell<Vec<u64>>) {
    if factors.get().len() != order + 1 {
        let mut vec = vec.borrow_mut();
        // Remove everything from the vector without freeing memory
        unsafe{ vec.set_len(0) };

        // The vector stores both the factors of the order and the order's derivative, and this is the
        // length necessary to contain those factors.
        let new_len = (order + 1) * 2 - 1;
        if vec.capacity() < new_len {
            let reserve_amount = new_len - vec.capacity();
            vec.reserve(reserve_amount);
        }

        {
            let order = order as u64;

            for k in 0..order + 1 {
                vec.push(combination(order, k));
            }

            for k in 0..order {
                vec.push(combination(order - 1, k));
            }
        }

        factors.set(RangeSlice::new(0, order + 1));
        dfactors.set(RangeSlice::new(order + 1, vec.len()));
    }
}

/// An n-order bezier polynomial
#[derive(Clone)]
pub struct NBezPoly<F, C = Vec<F>>
        where F: Float,
              C: AsRef<[F]> {
    points: C,
    factor_vec: RefCell<Vec<u64>>,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<F>
}

impl<F, C> From<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn from(container: C) -> NBezPoly<F, C> {
        NBezPoly::from_container(container)
    }
}

impl<F, C> NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    #[inline]
    pub fn from_container(points: C) -> NBezPoly<F, C> {
        if points.as_ref().len() >= 22 {
            panic!("Cannot create Bézier polynomials with an order >= 21")
        }

        NBezPoly {
            points: points,
            factor_vec: RefCell::new(Vec::new()),
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }

    unsafe fn interp_unchecked<I: Iterator<Item=F>>(t: F, factors: &[u64], iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = factors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;

        for point in iter {
            acc = acc + t.powi(factor as i32) *
                        t1.powi((order-factor) as i32) *
                        point *
                        F::from_u64(factors[factor]).unwrap();
            factor += 1;
        }
        acc
    }

    unsafe fn slope_unchecked<I: Iterator<Item=F>>(t: F, dfactors: &[u64], mut iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = dfactors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;
        let mut point_next = iter.next().unwrap();

        for point in iter {
            acc = acc + t.powi(factor as i32) *
                        t1.powi((order-factor) as i32) *
                        (point - point_next) *
                        F::from_u64(dfactors[factor] * (order + 1) as u64).unwrap();
            point_next = point;
            factor += 1;
        }
        acc
    }
}

impl<F, C> BezCurve<F> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    type Point = F;
    type Vector = F;
    type Elevated = NBezPoly<F>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[F]) -> Option<NBezPoly<F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);

        unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, &self.factor_vec.borrow()[self.factors.get().as_range()], points.iter().map(|f| *f)) }
    }

    fn slope_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);

        unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, &self.factor_vec.borrow()[self.dfactors.get().as_range()], points.iter().map(|f| *f)) }
    }

    fn elevate(&self) -> NBezPoly<F> {
        let points = self.points.as_ref();
        let order = self.order() + 1;
        let order_f = F::from_usize(order).unwrap();

        // Elevated points
        let mut el_points = Vec::with_capacity(order + 1);
        el_points.push(points[0]);

        let mut prev_p = points[0];
        for (i, p) in points.iter().map(|p| *p).enumerate().skip(1) {
            el_points.push(lerp(p, prev_p, F::from_usize(i).unwrap()/order_f));

            prev_p = p;
        }

        el_points.push(points[self.order()]);
        NBezPoly::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBezPoly<F, C>, NBezPoly<F, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }
}

impl<F, C> AsRef<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C> AsMut<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<F, C> Debug for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBezPoly")
            .field(&self.points)
            .finish()
    }
}

#[derive(Clone)]
pub struct NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    points: C,
    factor_vec: RefCell<Vec<u64>>,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,

    phantom: PhantomData<(F, P, V)>
}

impl<P, V, F, C> From<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn from(container: C) -> NBez<P, V, F, C> {
        NBez::from_container(container)
    }
}

impl<P, V, F, C> NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    /// Create a new `NBez` curve from a container
    pub fn from_container(container: C) -> NBez<P, V, F, C> {
        if container.as_ref().len() >= 22 {
            panic!("Cannot create Bézier curves with an order >= 21")
        }

        NBez {
            points: container,
            factor_vec: RefCell::new(Vec::new()),
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),

            phantom: PhantomData,
        }
    }

    /// Get the wrapped container, destroying the `NBez` curve
    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<P, V, F, C> BezCurve<F> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    type Point = P;
    type Vector = V;
    type Elevated = NBez<P, V, F, Vec<P>>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[P]) -> Option<NBez<P, V, F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();

        // Initialize a point by cloning one from the point list
        let mut point = points[0].clone();

        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);

        // Iterate over all elements of the point and set them to the interpolated value
        for (i, f) in point.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, &self.factor_vec.borrow()[self.factors.get().as_range()], iter) };
        }

        point
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();

        // Initialize a vector by cloning it from the point list and converting it into a vector
        let mut vector: V = points[0].clone().into();

        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);

        // Iterate over all elements of the vector and set them to the interpolated value
        for (i, f) in vector.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, &self.factor_vec.borrow()[self.dfactors.get().as_range()], iter) };
        }

        vector
    }

    fn elevate(&self) -> NBez<P, V, F, Vec<P>> {
        let points = self.points.as_ref();
        let order = F::from_usize(self.order() + 1).unwrap();

        let mut el_points = Vec::with_capacity(points.len() + 1);
        el_points.push(points[0].clone());

        let mut prev_p = points[0].clone();
        for (i, p) in points.iter().enumerate().skip(1) {
            // Push an arbitrary point onto the vector for modification
            el_points.push(p.clone());

            // Iterate over each dimension of the current (c) and previous (r) point and interpolate
            // between them
            for (d, (c, r)) in p.as_ref().iter().zip(prev_p.as_ref().iter()).map(|(c, r)| (*c, *r)).enumerate() {
                el_points[i].as_mut()[d] = lerp(c, r, F::from_usize(i).unwrap()/order);
            }
            prev_p = p.clone();
        }
        el_points.push(points[points.len()-1].clone());
        NBez::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBez<P, V, F, C>, NBez<P, V, F, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len() - 1
    }
}

impl<P, V, F, C> AsRef<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<P, V, F, C> AsMut<C> for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<P, V, F, C> Debug for NBez<P, V, F, C>
        where F: Float,
              C: AsRef<[P]> + Debug,
              P: Point<F>,
              V: Vector<F, P> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBez")
            .field(&self.points)
            .finish()
    }
}<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::{de, Deserialize, Deserializer};

/// How many `ChunkSize` blocks must be copied from the source file to
/// the target. The default value of -1 means all possible bytes
/// until the end of the file.
#[derive(PartialEq, Debug, Clone)]
pub enum Count {
    All,
    Limited(usize),
}

impl Default for Count {
    fn default() -> Self {
        Count::All
    }
}

impl<'de> Deserialize<'de> for Count {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        match isize::deserialize(deserializer)? {
            -1 => Ok(Count::All),
            n if n >= 0 => Ok(Count::Limited(n as usize)),
            n => Err(de::Error::custom(format!("Invalid count: {}", n))),
        }
    }
}

impl std::iter::Iterator for Count {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Count::All => Some(0),
            Count::Limited(ref mut n) => match n {
                0 => None,
                n => {
                    *n -= 1;
                    Some(*n)
                }
            },
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use pretty_assertions::assert_eq;
    use serde_json::json;

    #[derive(Debug, PartialEq, Deserialize)]
    struct Payload {
        #[serde(default)]
        count: Count,
    }

    #[test]
    fn deserialize() {
        assert_eq!(
            serde_json::from_value::<Payload>(json!({ "count": 0 })).unwrap(),
            Payload { count: Count::Limited(0) }
        );
    }

    #[test]
    fn default() {
        assert_eq!(
            serde_json::from_value::<Payload>(json!({})).unwrap(),
            Payload { count: Count::All }
        );
    }

    #[test]
    fn validation_of_minimal() {
        assert!(serde_json::from_value::<Payload>(json!({ "count": -2 })).is_err());
    }
}
<commit_msg>updatehub-package-schema: Avoid using casting from isize to usize<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::{de, Deserialize, Deserializer};

/// How many `ChunkSize` blocks must be copied from the source file to
/// the target. The default value of -1 means all possible bytes
/// until the end of the file.
#[derive(PartialEq, Debug, Clone)]
pub enum Count {
    All,
    Limited(isize),
}

impl Default for Count {
    fn default() -> Self {
        Count::All
    }
}

impl<'de> Deserialize<'de> for Count {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        match isize::deserialize(deserializer)? {
            -1 => Ok(Count::All),
            n if n >= 0 => Ok(Count::Limited(n)),
            n => Err(de::Error::custom(format!("Invalid count: {}", n))),
        }
    }
}

impl std::iter::Iterator for Count {
    type Item = isize;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Count::All => Some(0),
            Count::Limited(ref mut n) => match n {
                0 => None,
                n => {
                    *n -= 1;
                    Some(*n)
                }
            },
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use pretty_assertions::assert_eq;
    use serde_json::json;

    #[derive(Debug, PartialEq, Deserialize)]
    struct Payload {
        #[serde(default)]
        count: Count,
    }

    #[test]
    fn deserialize() {
        assert_eq!(
            serde_json::from_value::<Payload>(json!({ "count": 0 })).unwrap(),
            Payload { count: Count::Limited(0) }
        );
    }

    #[test]
    fn default() {
        assert_eq!(
            serde_json::from_value::<Payload>(json!({})).unwrap(),
            Payload { count: Count::All }
        );
    }

    #[test]
    fn validation_of_minimal() {
        assert!(serde_json::from_value::<Payload>(json!({ "count": -2 })).is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;

use std::hash::Hash;
use serde::Serialize;

use generic_array::{GenericArray, typenum};

pub type Checksum = GenericArray<u8, typenum::U32>;

/// The state associated with a resource. This is stored in the database and
/// used to determine if a resource has changed.
#[allow(dead_code)]
pub enum ResourceState {
    /// The state of the resource has never been computed. In this case, the
    /// resource must *never* be deleted. This state means that the build system
    /// has not taken "ownership" of this resource and has no right to delete
    /// it.
    Unknown,

    /// The resource does not exist.
    Missing,

    /// The resource exists and we have the checksum of its contents.
    Checksum(Checksum),
}

/// FIXME: Use a more abstract error type.
pub type Error = io::Error;

/// A resource is an abstract representation of some unit of system state. A
/// resource can be a file, directory, environment variable. The only thing we
/// are interested in doing with a resource is:
///
///  1. Getting its state so that we can determine if it has changed.
///  2. Deleting it when it is no longer needed.
///
/// A resource is merely an *identifier*. It should not store any state about
/// the actual thing it is referencing. The only state that can be stored with a
/// resource is `ResourceState`.
pub trait Resource: Serialize + Ord + PartialOrd + Eq + PartialEq + Hash {
    /// Gets the state of the resource. This is used to determine if it has
    /// changed.
    fn state(&self) -> Result<ResourceState, Error>;

    /// Deletes the resource. Care should be taken by the caller to not delete
    /// *input* resources. That is, resources that the build system did not
    /// produce. Deleting output resources is perfectly fine. There shall be no
    /// error if the resource already does not exist. Output resources should be
    /// deleting in reverse topological order such that files can get deleted
    /// before directories.
    fn delete(&self) -> Result<(), Error>;
}

/// A task is a routine to be executed that produces resources as outputs.
///
/// Most tasks will be of the `Command` type. That is, the execution of a
/// process with arguments.
///
/// Since a task is anything that can be executed, we can have other built-in
/// tasks to aid with cross-platform compatibility. For example:
///  * Copying a file or directory.
///  * Downloading a file.
///  * Creating a directory.
pub trait Task: Serialize + Ord + PartialOrd + Eq + PartialEq + Hash {
    /// Executes the task. The result of a task are the resources it used and
    /// the resources it output. These are its *implicit* inputs and outputs.
    /// Ideally, the *explicit* inputs and outputs are a subset of the
    /// *implicit* inputs and outputs.
    fn execute(&self) -> Result<(), String>;
}
<commit_msg>Ensure all resource and task types implement fmt::Display<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::fmt;
use std::io;

use std::hash::Hash;
use serde::Serialize;

use generic_array::{GenericArray, typenum};

pub type Checksum = GenericArray<u8, typenum::U32>;

/// The state associated with a resource. This is stored in the database and
/// used to determine if a resource has changed.
#[allow(dead_code)]
pub enum ResourceState {
    /// The state of the resource has never been computed. In this case, the
    /// resource must *never* be deleted. This state means that the build system
    /// has not taken "ownership" of this resource and has no right to delete
    /// it.
    Unknown,

    /// The resource does not exist.
    Missing,

    /// The resource exists and we have the checksum of its contents.
    Checksum(Checksum),
}

/// FIXME: Use a more abstract error type.
pub type Error = io::Error;

/// A resource is an abstract representation of some unit of system state. A
/// resource can be a file, directory, environment variable. The only thing we
/// are interested in doing with a resource is:
///
///  1. Getting its state so that we can determine if it has changed.
///  2. Deleting it when it is no longer needed.
///
/// A resource is merely an *identifier*. It should not store any state about
/// the actual thing it is referencing. The only state that can be stored with a
/// resource is `ResourceState`.
pub trait Resource: Serialize + Ord + PartialOrd + Eq + PartialEq + Hash + fmt::Display {
    /// Gets the state of the resource. This is used to determine if it has
    /// changed.
    fn state(&self) -> Result<ResourceState, Error>;

    /// Deletes the resource. Care should be taken by the caller to not delete
    /// *input* resources. That is, resources that the build system did not
    /// produce. Deleting output resources is perfectly fine. There shall be no
    /// error if the resource already does not exist. Output resources should be
    /// deleting in reverse topological order such that files can get deleted
    /// before directories.
    fn delete(&self) -> Result<(), Error>;
}

/// A task is a routine to be executed that produces resources as outputs.
///
/// Most tasks will be of the `Command` type. That is, the execution of a
/// process with arguments.
///
/// Since a task is anything that can be executed, we can have other built-in
/// tasks to aid with cross-platform compatibility. For example:
///  * Copying a file or directory.
///  * Downloading a file.
///  * Creating a directory.
pub trait Task: Serialize + Ord + PartialOrd + Eq + PartialEq + Hash + fmt::Display {
    /// Executes the task. The result of a task are the resources it used and
    /// the resources it output. These are its *implicit* inputs and outputs.
    /// Ideally, the *explicit* inputs and outputs are a subset of the
    /// *implicit* inputs and outputs.
    fn execute(&self) -> Result<(), String>;
}
<|endoftext|>