<commit_before>#![crate_id = "rustic"]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;

use std::io::fs;
use std::io::process::{Command,ExitSignal,ExitStatus,ProcessOutput};
use std::os;
use std::str;

use tmpdir::TmpDir;

mod rand;
mod tmpdir;

// FIXME Need a better way to detect which argument is the crate file
fn is_crate(arg: &str) -> bool {
    arg.ends_with(".rs")
}

fn main() {
    let args = os::args();
    let args = args.slice_from(1);

    // If `--run` is not in the arguments: pass all the arguments to `rustc`
    if args.iter().all(|arg| arg.as_slice() != "--run") {
        let mut cmd = Command::new("rustc");
        cmd.args(args);

        info!("cwd: . | cmd: `{}`", cmd);
        // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
        match cmd.output() {
            Err(e) => fail!("`{}` failed: {}", cmd, e),
            Ok(ProcessOutput { output: out, error: err, status: exit }) => {
                match exit {
                    ExitSignal(exit) => os::set_exit_status(exit),
                    ExitStatus(exit) => os::set_exit_status(exit),
                }

                print!("{}", str::from_utf8_lossy(out.as_slice()));
                print!("{}", str::from_utf8_lossy(err.as_slice()));

                return;
            },
        }
    }

    // Separate the crate file from the other arguments
    let current_dir = os::getcwd();
    let crate_path = match args.iter().find(|arg| is_crate(arg.as_slice())) {
        Some(arg) => current_dir.join(arg.as_slice()),
        None => fail!("Didn't find a crate file in the arguments passed: {}",
                      args),
    };
    let args: Vec<&str> = args.iter().filter_map(|arg| {
        let arg = arg.as_slice();
        if is_crate(arg) { None } else { Some(arg) }
    }).collect();

    let tmpdir = TmpDir::new();
    let tmpdir_path = tmpdir.path();
    let tmpdir_display = tmpdir_path.display();

    // Before `--run`: arguments for the compiler
    let mut splitted_args = args.as_slice().split(|&flag| flag == "--run");
    let rustc_args = splitted_args.next().unwrap();

    // TODO `--crate-type=lib` should also be forbidden
    // XXX What if the crate has a `crate_type=*lib` attribute?
    if rustc_args.iter().any(|&flag| flag == "--out-dir") {
        fail!("Can't use both `--out-dir` and `--run` flags at the same time");
    }

    // Compile
    let mut cmd = Command::new("rustc");
    cmd.args(rustc_args).arg(crate_path);
    info!("cwd: {} | cmd: `{}`", tmpdir_display, cmd);
    // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
    match cmd.cwd(tmpdir_path).output() {
        Err(e) => fail!("`{}`: {}", cmd, e),
        Ok(ProcessOutput { output: out, error: err, status: exit }) => {
            let exit_code = match exit {
                ExitSignal(code) => code,
                ExitStatus(code) => code,
            };

            print!("{}", str::from_utf8_lossy(out.as_slice()));
            print!("{}", str::from_utf8_lossy(err.as_slice()));

            if !exit.success() {
                os::set_exit_status(exit_code);
                return;
            }
        },
    }

    // Look for the produced binary
    let mut cmd = match fs::readdir(tmpdir_path) {
        Err(e) => fail!("`ls {}`: {}", tmpdir_display, e),
        Ok(paths) => match paths.as_slice().get(0) {
            Some(path) => Command::new(path),
            None => fail!("no binary found in {}", tmpdir_display),
        }
    };

    // After `--run`: arguments for the executable
    let executable_args = splitted_args.next().unwrap();
    cmd.args(executable_args);

    // Execute
    info!("cwd: . | cmd: `{}`", cmd);
    // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
    match cmd.output() {
        Err(e) => fail!("`{}`: {}", cmd, e),
        Ok(ProcessOutput { output: out, error: err, status: exit }) => {
            let exit_code = match exit {
                ExitSignal(code) => code,
                ExitStatus(code) => code,
            };

            print!("{}", str::from_utf8_lossy(out.as_slice()));
            print!("{}", str::from_utf8_lossy(err.as_slice()));

            os::set_exit_status(exit_code);
        }
    }
}
<commit_msg>Be more cautious when dealing with absolute paths. Closes #2<commit_after>#![crate_id = "rustic"]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;

use std::io::fs;
use std::io::process::{Command,ExitSignal,ExitStatus,ProcessOutput};
use std::os;
use std::str;

use tmpdir::TmpDir;

mod rand;
mod tmpdir;

// FIXME Need a better way to detect which argument is the crate file
fn is_crate(arg: &str) -> bool {
    arg.ends_with(".rs")
}

fn main() {
    let args = os::args();
    let args = args.slice_from(1);

    // If `--run` is not in the arguments: pass all the arguments to `rustc`
    if args.iter().all(|arg| arg.as_slice() != "--run") {
        let mut cmd = Command::new("rustc");
        cmd.args(args);

        info!("cwd: . | cmd: `{}`", cmd);
        // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
        match cmd.output() {
            Err(e) => fail!("`{}` failed: {}", cmd, e),
            Ok(ProcessOutput { output: out, error: err, status: exit }) => {
                match exit {
                    ExitSignal(exit) => os::set_exit_status(exit),
                    ExitStatus(exit) => os::set_exit_status(exit),
                }

                print!("{}", str::from_utf8_lossy(out.as_slice()));
                print!("{}", str::from_utf8_lossy(err.as_slice()));

                return;
            },
        }
    }

    // Separate the crate file from the other arguments
    let current_dir = os::getcwd();
    let crate_path = match args.iter().find(|arg| is_crate(arg.as_slice())) {
        Some(arg) => {
            let path = Path::new(arg.as_slice());
            if path.is_absolute() {
                path
            } else {
                current_dir.join(path)
            }
        }
        None => fail!("Didn't find a crate file in the arguments passed: {}",
                      args),
    };
    let args: Vec<&str> = args.iter().filter_map(|arg| {
        let arg = arg.as_slice();
        if is_crate(arg) { None } else { Some(arg) }
    }).collect();

    let tmpdir = TmpDir::new();
    let tmpdir_path = tmpdir.path();
    let tmpdir_display = tmpdir_path.display();

    // Before `--run`: arguments for the compiler
    let mut splitted_args = args.as_slice().split(|&flag| flag == "--run");
    let rustc_args = splitted_args.next().unwrap();

    // TODO `--crate-type=lib` should also be forbidden
    // XXX What if the crate has a `crate_type=*lib` attribute?
    if rustc_args.iter().any(|&flag| flag == "--out-dir") {
        fail!("Can't use both `--out-dir` and `--run` flags at the same time");
    }

    // Compile
    let mut cmd = Command::new("rustc");
    cmd.args(rustc_args).arg(crate_path);
    info!("cwd: {} | cmd: `{}`", tmpdir_display, cmd);
    // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
    match cmd.cwd(tmpdir_path).output() {
        Err(e) => fail!("`{}`: {}", cmd, e),
        Ok(ProcessOutput { output: out, error: err, status: exit }) => {
            let exit_code = match exit {
                ExitSignal(code) => code,
                ExitStatus(code) => code,
            };

            print!("{}", str::from_utf8_lossy(out.as_slice()));
            print!("{}", str::from_utf8_lossy(err.as_slice()));

            if !exit.success() {
                os::set_exit_status(exit_code);
                return;
            }
        },
    }

    // Look for the produced binary
    let mut cmd = match fs::readdir(tmpdir_path) {
        Err(e) => fail!("`ls {}`: {}", tmpdir_display, e),
        Ok(paths) => match paths.as_slice().get(0) {
            Some(path) => Command::new(path),
            None => fail!("no binary found in {}", tmpdir_display),
        }
    };

    // After `--run`: arguments for the executable
    let executable_args = splitted_args.next().unwrap();
    cmd.args(executable_args);

    // Execute
    info!("cwd: . | cmd: `{}`", cmd);
    // FIXME Replace `output` for `spawn`, and redirect child std{out,err}
    match cmd.output() {
        Err(e) => fail!("`{}`: {}", cmd, e),
        Ok(ProcessOutput { output: out, error: err, status: exit }) => {
            let exit_code = match exit {
                ExitSignal(code) => code,
                ExitStatus(code) => code,
            };

            print!("{}", str::from_utf8_lossy(out.as_slice()));
            print!("{}", str::from_utf8_lossy(err.as_slice()));

            os::set_exit_status(exit_code);
        }
    }
}
<|endoftext|>


<commit_before>extern crate z80e_core_rust;
extern crate goss;
mod mmu;
mod stdio_dev;
use z80e_core_rust::Z80;
use mmu::{ Memory, MMU };
use stdio_dev::{ StdioDevice, ConcurrentDevice };
use std::io::{ Read, Write };
use std::str::FromStr;
use std::env;
use std::fs::File;
use std::sync::{ Arc };
use std::sync::atomic::{ AtomicBool, Ordering };
use std::thread;

struct BankImage {
    name: String,
    bank: usize,
    file: File,
}

const NUM_BANKS: u8 = 1;

fn main() {
    let mut num_banks = NUM_BANKS;
    let mut stderr = std::io::stderr();
    let memory;
    let mut mmu;
    {
        let mut images: Vec<BankImage> = Vec::new();
        match goss::getopt(env::args(), "l:n:") {
            Ok(got_opt) => {
                for opt in got_opt.opts {
                    match opt.switch {
                        'n' => {
                            let arg = opt.argument.unwrap();
                            num_banks = match usize::from_str(&arg[..]) {
                                Ok(x) => {
                                    if x > u8::max_value() as usize {
                                        let _ = writeln!(stderr, "-n: Bad argument: {}", arg);
                                        panic!("Bank too big. (max: {})", u8::max_value() as usize);
                                    }
                                    x as u8
                                },
                                Err(err) => {
                                    let _ = writeln!(stderr, "-n: Bad argument: {} ← {}", arg, err);
                                    panic!("Unable to comprehend number.")
                                }
                            }
                        },
                        'l' => {
                            let mut bank = 0;
                            let arg = opt.argument.unwrap();
                            let subopts: Vec<&str> = arg.split('=').collect();
                            let file_name;
                            if subopts.len() > 1 {
                                match usize::from_str(&(subopts[0])[..]) {
                                    Ok(x) => bank = x,
                                    Err(err) => {
                                        let _ = writeln!(stderr, "-l: Bad argument: {} → {} ← {}", arg, subopts[0], err);
                                        panic!("Unable to comprehend number.");
                                    },
                                }
                                file_name = subopts[1].clone();
                            } else {
                                file_name = subopts[0].clone();
                            }
                            let mut file = match File::open(file_name) {
                                Ok(file) => file,
                                Err(err) => {
                                    let _ = writeln!(stderr, "-l: Unable to open image: {} → {}", file_name, err);
                                    panic!("I/O error.");
                                },
                            };
                            images.push(BankImage {
                                name: file_name.to_string(),
                                bank: bank,
                                file: file,
                            });
                        },
                        switch @ _ => { let _ = writeln!(stderr, "Unhandled switch: -{}", switch); },
                    }
                }
            },
            Err(err) => {
                match err {
                    goss::Error::BadOptionString => {
                        let _ = writeln!(stderr, "GOSS is broken.");
                        panic!("The option parsing library claims we're using it wrong.'");
                    },
                    goss::Error::UnknownSwitch(switch) => {
                        let _ = writeln!(stderr, "Unknown switch: {}", switch);
                        panic!("You have specified an unrecognized switch.");
                    },
                    goss::Error::MissingArgument(switch) => {
                        let _ = writeln!(stderr, "Missing argument to -{}.", switch);
                        panic!("You didn't specify a required optarg or you messed up your switch order.");
                    },
                }
            },
        }
        memory = Memory::new(num_banks);
        mmu = MMU::new(memory.clone());
        let mut bank_0_initialized = false;
        for image in images.iter_mut() {
            if image.bank >= num_banks as usize {
                let _ = writeln!(stderr, "Invalid bank: {} for image {}", image.bank, image.name);
                panic!("Total number of banks too low for index. (Number of banks: {})", num_banks);
            }
            let mut image_temp: Vec<u8> = Vec::new();
            match image.file.read_to_end(&mut image_temp) {
                Ok(_) => {
                    if image_temp.len() > mmu::BANK_SIZE {
                        let _ = writeln!(stderr, "Invalid image: {}", image.name);
                        panic!("The file is too large for the bank size ({} bytes).", mmu::BANK_SIZE);
                    }
                },
                Err(err) => {
                    let _ = writeln!(stderr, "-l: Read error: {}", err);
                    panic!("Unable to read bank image.");
                }
            }
            for i in 0..image_temp.len() {
                let mut bank = match memory.banks[image.bank].lock() {
                    Ok(x) => x,
                    Err(err) => {
                        let _ = writeln!(stderr, "-l: Mutex error: {}", err);
                        panic!("Unable to acquire mutex for bank {}.", image.bank);
                    }
                };
                bank[i] = image_temp[i];
            }
            if image.bank == 0 { bank_0_initialized = true; };
        }
        if !bank_0_initialized {
            let _ = writeln!(stderr, "Memory not ready.");
            panic!("You must load an image for bank 0. (-l)")
        }
    }
    let mut cpu = Z80::new(&mut mmu);
    cpu.install_device(0, &mut mmu.bank_registers[0]);
    cpu.install_device(1, &mut mmu.bank_registers[1]);
    cpu.install_device(2, &mut mmu.bank_registers[2]);
    cpu.install_device(3, &mut mmu.bank_registers[3]);

    let device = StdioDevice::new();
    cpu.install_device(4, &mut device.get_control_port());
    cpu.install_device(5, &mut device.get_data_port());

    let die = Arc::new(AtomicBool::new(false));
    let mut device_threads = Vec::new();
    {
        let mut reader = device.get_reader();
        let die = die.clone();
        device_threads.push(thread::spawn(move || reader.run(die)));
    }
    {
        let mut writer = device.get_writer();
        let die = die.clone();
        device_threads.push(thread::spawn(move || writer.run(die)));
    }

    let cpu = Arc::new(&cpu);
    let _ = cpu.execute(0);
    die.store(true, Ordering::Release);
    for thread in device_threads {
        let _ = thread.join().unwrap();
    }
    println!("Exiting successfully.")
}
<commit_msg>Add check for excess command line arguments.<commit_after>extern crate z80e_core_rust;
extern crate goss;
mod mmu;
mod stdio_dev;
use z80e_core_rust::Z80;
use mmu::{ Memory, MMU };
use stdio_dev::{ StdioDevice, ConcurrentDevice };
use std::io::{ Read, Write };
use std::str::FromStr;
use std::env;
use std::fs::File;
use std::sync::{ Arc };
use std::sync::atomic::{ AtomicBool, Ordering };
use std::thread;

struct BankImage {
    name: String,
    bank: usize,
    file: File,
}

const NUM_BANKS: u8 = 1;

fn main() {
    let mut num_banks = NUM_BANKS;
    let mut stderr = std::io::stderr();
    let memory;
    let mut mmu;
    {
        let mut images: Vec<BankImage> = Vec::new();
        match goss::getopt(env::args(), "l:n:") {
            Ok(mut got_opt) => {
                for opt in got_opt.opts {
                    match opt.switch {
                        'n' => {
                            let arg = opt.argument.unwrap();
                            num_banks = match usize::from_str(&arg[..]) {
                                Ok(x) => {
                                    if x > u8::max_value() as usize {
                                        let _ = writeln!(stderr, "-n: Bad argument: {}", arg);
                                        panic!("Bank too big. (max: {})", u8::max_value() as usize);
                                    }
                                    x as u8
                                },
                                Err(err) => {
                                    let _ = writeln!(stderr, "-n: Bad argument: {} ← {}", arg, err);
                                    panic!("Unable to comprehend number.")
                                }
                            }
                        },
                        'l' => {
                            let mut bank = 0;
                            let arg = opt.argument.unwrap();
                            let subopts: Vec<&str> = arg.split('=').collect();
                            let file_name;
                            if subopts.len() > 1 {
                                match usize::from_str(&(subopts[0])[..]) {
                                    Ok(x) => bank = x,
                                    Err(err) => {
                                        let _ = writeln!(stderr, "-l: Bad argument: {} → {} ← {}", arg, subopts[0], err);
                                        panic!("Unable to comprehend number.");
                                    },
                                }
                                file_name = subopts[1].clone();
                            } else {
                                file_name = subopts[0].clone();
                            }
                            let mut file = match File::open(file_name) {
                                Ok(file) => file,
                                Err(err) => {
                                    let _ = writeln!(stderr, "-l: Unable to open image: {} → {}", file_name, err);
                                    panic!("I/O error.");
                                },
                            };
                            images.push(BankImage {
                                name: file_name.to_string(),
                                bank: bank,
                                file: file,
                            });
                        },
                        switch @ _ => { let _ = writeln!(stderr, "Unhandled switch: -{}", switch); },
                    }
                }
                match got_opt.rest.next() {
                    Some(x) => {
                        let _ = writeln!(stderr, "Excess argument: {}", x);
                        panic!("You specified an argument no switch was expecting.");
                    },
                    None => (),
                }
            },
            Err(err) => {
                match err {
                    goss::Error::BadOptionString => {
                        let _ = writeln!(stderr, "GOSS is broken.");
                        panic!("The option parsing library claims we're using it wrong.'");
                    },
                    goss::Error::UnknownSwitch(switch) => {
                        let _ = writeln!(stderr, "Unknown switch: {}", switch);
                        panic!("You have specified an unrecognized switch.");
                    },
                    goss::Error::MissingArgument(switch) => {
                        let _ = writeln!(stderr, "Missing argument to -{}.", switch);
                        panic!("You didn't specify a required optarg or you messed up your switch order.");
                    },
                }
            },
        }
        memory = Memory::new(num_banks);
        mmu = MMU::new(memory.clone());
        let mut bank_0_initialized = false;
        for image in images.iter_mut() {
            if image.bank >= num_banks as usize {
                let _ = writeln!(stderr, "Invalid bank: {} for image {}", image.bank, image.name);
                panic!("Total number of banks too low for index. (Number of banks: {})", num_banks);
            }
            let mut image_temp: Vec<u8> = Vec::new();
            match image.file.read_to_end(&mut image_temp) {
                Ok(_) => {
                    if image_temp.len() > mmu::BANK_SIZE {
                        let _ = writeln!(stderr, "Invalid image: {}", image.name);
                        panic!("The file is too large for the bank size ({} bytes).", mmu::BANK_SIZE);
                    }
                },
                Err(err) => {
                    let _ = writeln!(stderr, "-l: Read error: {}", err);
                    panic!("Unable to read bank image.");
                }
            }
            for i in 0..image_temp.len() {
                let mut bank = match memory.banks[image.bank].lock() {
                    Ok(x) => x,
                    Err(err) => {
                        let _ = writeln!(stderr, "-l: Mutex error: {}", err);
                        panic!("Unable to acquire mutex for bank {}.", image.bank);
                    }
                };
                bank[i] = image_temp[i];
            }
            if image.bank == 0 { bank_0_initialized = true; };
        }
        if !bank_0_initialized {
            let _ = writeln!(stderr, "Memory not ready.");
            panic!("You must load an image for bank 0. (-l)")
        }
    }
    let mut cpu = Z80::new(&mut mmu);
    cpu.install_device(0, &mut mmu.bank_registers[0]);
    cpu.install_device(1, &mut mmu.bank_registers[1]);
    cpu.install_device(2, &mut mmu.bank_registers[2]);
    cpu.install_device(3, &mut mmu.bank_registers[3]);

    let device = StdioDevice::new();
    cpu.install_device(4, &mut device.get_control_port());
    cpu.install_device(5, &mut device.get_data_port());

    let die = Arc::new(AtomicBool::new(false));
    let mut device_threads = Vec::new();
    {
        let mut reader = device.get_reader();
        let die = die.clone();
        device_threads.push(thread::spawn(move || reader.run(die)));
    }
    {
        let mut writer = device.get_writer();
        let die = die.clone();
        device_threads.push(thread::spawn(move || writer.run(die)));
    }

    let cpu = Arc::new(&cpu);
    let _ = cpu.execute(0);
    die.store(true, Ordering::Release);
    for thread in device_threads {
        let _ = thread.join().unwrap();
    }
    println!("Exiting successfully.")
}
<|endoftext|>


<commit_before>// Copyright 2015 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An ultra-light private math library to make our short lives easier whilst
//! implementing super-complex noise stuff.

use std::num::{self, Float, NumCast};
use std::ops::{Add, Sub, Mul};

/// Cast a numeric type without having to unwrap - we don't expect any overflow
/// errors...
pub fn cast<T: NumCast, U: NumCast>(x: T) -> U {
    num::cast(x).unwrap()
}

/// Linearly interpolates between the values `f0` and `f1` by the factor `u`
pub fn lerp<T: Float>(u: T, f0: T, f1: T) -> T {
    u * (f1 - f0) + f0
}

/// Burp ⊙︿⊙
pub fn bilerp<T: Float>([u, v]: Vector2<T>, f00: T, f10: T, f01: T, f11: T) -> T {
    lerp(v, lerp(u, f00, f10),
            lerp(u, f01, f11))
}

/// Glurp ⊙▃⊙
pub fn trilerp<T: Float>([u, v, w]: Vector3<T>, f000: T, f100: T, f010: T, f110: T, f001: T, f101: T, f011: T, f111: T) -> T {
    lerp(w, bilerp([u, v], f000, f100, f010, f110),
            bilerp([u, v], f001, f101, f011, f111))
}

/// Flurp ⊙﹏⊙
pub fn quadlerp<T: Float>([u, v, w, x]: Vector4<T>, f0000: T, f1000: T, f0001: T, f1001: T, f0010: T, f1010: T, f0011: T, f1011: T, f0100: T, f1100: T, f0101: T, f1101: T, f0110: T, f1110: T, f0111: T, f1111: T) -> T {
    lerp(x, trilerp([u, v, w], f0000, f1000, f0001, f1001, f0010, f1010, f0011, f1011),
            trilerp([u, v, w], f0100, f1100, f0101, f1101, f0110, f1110, f0111, f1111))
}

/// Swurvep ◔ ᴗ ◔
pub fn scurve5<T: Float>(t: T) -> T {
    t * t * t * (t * (t * cast(6) - cast(15)) + cast(10))
}

/// Raises the number to the power of `4`
pub fn pow4<T: Float>(x: T) -> T { x * x * x * x }

/// A 2-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point2<T> = [T; 2];

/// A 3-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point3<T> = [T; 3];

/// A 4-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point4<T> = [T; 4];

/// A 2-dimensional vector, for internal use.
pub type Vector2<T> = [T; 2];
/// A 3-dimensional vector, for internal use.
pub type Vector3<T> = [T; 3];
/// A 4-dimensional vector, for internal use.
pub type Vector4<T> = [T; 4];

pub fn map2<T, U, F: Fn(T) -> U>([ax, ay        ]: Vector2<T>, f: F) -> Vector2<U> { [f(ax), f(ay)] }
pub fn map3<T, U, F: Fn(T) -> U>([ax, ay, az    ]: Vector3<T>, f: F) -> Vector3<U> { [f(ax), f(ay), f(az)] }
pub fn map4<T, U, F: Fn(T) -> U>([ax, ay, az, aw]: Vector4<T>, f: F) -> Vector4<U> { [f(ax), f(ay), f(az), f(aw)] }

pub fn zip_with2<T, U, V, F: Fn(T, U) -> V>([ax, ay        ]: Vector2<T>, [bx, by        ]: Vector2<U>, f: F) -> Vector2<V> { [f(ax, bx), f(ay, by)] }
pub fn zip_with3<T, U, V, F: Fn(T, U) -> V>([ax, ay, az    ]: Vector3<T>, [bx, by, bz    ]: Vector3<U>, f: F) -> Vector3<V> { [f(ax, bx), f(ay, by), f(az, bz)] }
pub fn zip_with4<T, U, V, F: Fn(T, U) -> V>([ax, ay, az, aw]: Vector4<T>, [bx, by, bz, bw]: Vector4<U>, f: F) -> Vector4<V> { [f(ax, bx), f(ay, by), f(az, bz), f(aw, bw)] }

pub fn fold2<T, F: Fn(T, T) -> T>([ax, ay        ]: Vector2<T>, f: F) -> T { f(ax, ay) }
pub fn fold3<T, F: Fn(T, T) -> T>([ax, ay, az    ]: Vector3<T>, f: F) -> T { f(f(ax, ay), az) }
pub fn fold4<T, F: Fn(T, T) -> T>([ax, ay, az, aw]: Vector4<T>, f: F) -> T { f(f(f(ax, ay), az), aw) }

pub fn add2<T: Add<T, Output = T>>(a: Point2<T>, b: Vector2<T>) -> Point2<T> { zip_with2(a, b, Add::add) }
pub fn add3<T: Add<T, Output = T>>(a: Point3<T>, b: Vector3<T>) -> Point3<T> { zip_with3(a, b, Add::add) }
pub fn add4<T: Add<T, Output = T>>(a: Point4<T>, b: Vector4<T>) -> Point4<T> { zip_with4(a, b, Add::add) }

pub fn sub2<T: Sub<T, Output = T>>(a: Point2<T>, b: Point2<T>) -> Vector2<T> { zip_with2(a, b, Sub::sub) }
pub fn sub3<T: Sub<T, Output = T>>(a: Point3<T>, b: Point3<T>) -> Vector3<T> { zip_with3(a, b, Sub::sub) }
pub fn sub4<T: Sub<T, Output = T>>(a: Point4<T>, b: Point4<T>) -> Vector4<T> { zip_with4(a, b, Sub::sub) }

pub fn mul2<T: Mul<T, Output = T> + Copy>(a: Vector2<T>, b: T) -> Vector2<T> { zip_with2(a, const2(b), Mul::mul) }
pub fn mul3<T: Mul<T, Output = T> + Copy>(a: Vector3<T>, b: T) -> Vector3<T> { zip_with3(a, const3(b), Mul::mul) }
pub fn mul4<T: Mul<T, Output = T> + Copy>(a: Vector4<T>, b: T) -> Vector4<T> { zip_with4(a, const4(b), Mul::mul) }

pub fn dot2<T: Float>(a: Vector2<T>, b: Vector2<T>) -> T { fold2(zip_with2(a, b, Mul::mul), Add::add) }
pub fn dot3<T: Float>(a: Vector3<T>, b: Vector3<T>) -> T { fold3(zip_with3(a, b, Mul::mul), Add::add) }
pub fn dot4<T: Float>(a: Vector4<T>, b: Vector4<T>) -> T { fold4(zip_with4(a, b, Mul::mul), Add::add) }

pub fn const2<T: Copy>(x: T) -> Vector2<T> { [x, x] }
pub fn const3<T: Copy>(x: T) -> Vector3<T> { [x, x, x] }
pub fn const4<T: Copy>(x: T) -> Vector4<T> { [x, x, x, x] }

pub fn one2<T: Copy + NumCast>() -> Vector2<T> { cast2(const2(1)) }
pub fn one3<T: Copy + NumCast>() -> Vector3<T> { cast3(const3(1)) }
pub fn one4<T: Copy + NumCast>() -> Vector4<T> { cast4(const4(1)) }

pub fn cast2<T: NumCast + Copy, U: NumCast + Copy>(x: Point2<T>) -> Point2<U> { map2(x, cast) }
pub fn cast3<T: NumCast + Copy, U: NumCast + Copy>(x: Point3<T>) -> Point3<U> { map3(x, cast) }
pub fn cast4<T: NumCast + Copy, U: NumCast + Copy>(x: Point4<T>) -> Point4<U> { map4(x, cast) }
<commit_msg>Fix wording<commit_after>// Copyright 2015 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An ultra-light private math library to make our short lives easier as we
//! implement super-complex noise stuff.

use std::num::{self, Float, NumCast};
use std::ops::{Add, Sub, Mul};

/// Cast a numeric type without having to unwrap - we don't expect any overflow
/// errors...
pub fn cast<T: NumCast, U: NumCast>(x: T) -> U {
    num::cast(x).unwrap()
}

/// Linearly interpolates between the values `f0` and `f1` by the factor `u`
pub fn lerp<T: Float>(u: T, f0: T, f1: T) -> T {
    u * (f1 - f0) + f0
}

/// Burp ⊙︿⊙
pub fn bilerp<T: Float>([u, v]: Vector2<T>, f00: T, f10: T, f01: T, f11: T) -> T {
    lerp(v, lerp(u, f00, f10),
            lerp(u, f01, f11))
}

/// Glurp ⊙▃⊙
pub fn trilerp<T: Float>([u, v, w]: Vector3<T>, f000: T, f100: T, f010: T, f110: T, f001: T, f101: T, f011: T, f111: T) -> T {
    lerp(w, bilerp([u, v], f000, f100, f010, f110),
            bilerp([u, v], f001, f101, f011, f111))
}

/// Flurp ⊙﹏⊙
pub fn quadlerp<T: Float>([u, v, w, x]: Vector4<T>, f0000: T, f1000: T, f0001: T, f1001: T, f0010: T, f1010: T, f0011: T, f1011: T, f0100: T, f1100: T, f0101: T, f1101: T, f0110: T, f1110: T, f0111: T, f1111: T) -> T {
    lerp(x, trilerp([u, v, w], f0000, f1000, f0001, f1001, f0010, f1010, f0011, f1011),
            trilerp([u, v, w], f0100, f1100, f0101, f1101, f0110, f1110, f0111, f1111))
}

/// Swurvep ◔ ᴗ ◔
pub fn scurve5<T: Float>(t: T) -> T {
    t * t * t * (t * (t * cast(6) - cast(15)) + cast(10))
}

/// Raises the number to the power of `4`
pub fn pow4<T: Float>(x: T) -> T { x * x * x * x }

/// A 2-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point2<T> = [T; 2];

/// A 3-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point3<T> = [T; 3];

/// A 4-dimensional point. This is a fixed sized array, so should be compatible
/// with most linear algebra libraries.
pub type Point4<T> = [T; 4];

/// A 2-dimensional vector, for internal use.
pub type Vector2<T> = [T; 2];
/// A 3-dimensional vector, for internal use.
pub type Vector3<T> = [T; 3];
/// A 4-dimensional vector, for internal use.
pub type Vector4<T> = [T; 4];

pub fn map2<T, U, F: Fn(T) -> U>([ax, ay        ]: Vector2<T>, f: F) -> Vector2<U> { [f(ax), f(ay)] }
pub fn map3<T, U, F: Fn(T) -> U>([ax, ay, az    ]: Vector3<T>, f: F) -> Vector3<U> { [f(ax), f(ay), f(az)] }
pub fn map4<T, U, F: Fn(T) -> U>([ax, ay, az, aw]: Vector4<T>, f: F) -> Vector4<U> { [f(ax), f(ay), f(az), f(aw)] }

pub fn zip_with2<T, U, V, F: Fn(T, U) -> V>([ax, ay        ]: Vector2<T>, [bx, by        ]: Vector2<U>, f: F) -> Vector2<V> { [f(ax, bx), f(ay, by)] }
pub fn zip_with3<T, U, V, F: Fn(T, U) -> V>([ax, ay, az    ]: Vector3<T>, [bx, by, bz    ]: Vector3<U>, f: F) -> Vector3<V> { [f(ax, bx), f(ay, by), f(az, bz)] }
pub fn zip_with4<T, U, V, F: Fn(T, U) -> V>([ax, ay, az, aw]: Vector4<T>, [bx, by, bz, bw]: Vector4<U>, f: F) -> Vector4<V> { [f(ax, bx), f(ay, by), f(az, bz), f(aw, bw)] }

pub fn fold2<T, F: Fn(T, T) -> T>([ax, ay        ]: Vector2<T>, f: F) -> T { f(ax, ay) }
pub fn fold3<T, F: Fn(T, T) -> T>([ax, ay, az    ]: Vector3<T>, f: F) -> T { f(f(ax, ay), az) }
pub fn fold4<T, F: Fn(T, T) -> T>([ax, ay, az, aw]: Vector4<T>, f: F) -> T { f(f(f(ax, ay), az), aw) }

pub fn add2<T: Add<T, Output = T>>(a: Point2<T>, b: Vector2<T>) -> Point2<T> { zip_with2(a, b, Add::add) }
pub fn add3<T: Add<T, Output = T>>(a: Point3<T>, b: Vector3<T>) -> Point3<T> { zip_with3(a, b, Add::add) }
pub fn add4<T: Add<T, Output = T>>(a: Point4<T>, b: Vector4<T>) -> Point4<T> { zip_with4(a, b, Add::add) }

pub fn sub2<T: Sub<T, Output = T>>(a: Point2<T>, b: Point2<T>) -> Vector2<T> { zip_with2(a, b, Sub::sub) }
pub fn sub3<T: Sub<T, Output = T>>(a: Point3<T>, b: Point3<T>) -> Vector3<T> { zip_with3(a, b, Sub::sub) }
pub fn sub4<T: Sub<T, Output = T>>(a: Point4<T>, b: Point4<T>) -> Vector4<T> { zip_with4(a, b, Sub::sub) }

pub fn mul2<T: Mul<T, Output = T> + Copy>(a: Vector2<T>, b: T) -> Vector2<T> { zip_with2(a, const2(b), Mul::mul) }
pub fn mul3<T: Mul<T, Output = T> + Copy>(a: Vector3<T>, b: T) -> Vector3<T> { zip_with3(a, const3(b), Mul::mul) }
pub fn mul4<T: Mul<T, Output = T> + Copy>(a: Vector4<T>, b: T) -> Vector4<T> { zip_with4(a, const4(b), Mul::mul) }

pub fn dot2<T: Float>(a: Vector2<T>, b: Vector2<T>) -> T { fold2(zip_with2(a, b, Mul::mul), Add::add) }
pub fn dot3<T: Float>(a: Vector3<T>, b: Vector3<T>) -> T { fold3(zip_with3(a, b, Mul::mul), Add::add) }
pub fn dot4<T: Float>(a: Vector4<T>, b: Vector4<T>) -> T { fold4(zip_with4(a, b, Mul::mul), Add::add) }

pub fn const2<T: Copy>(x: T) -> Vector2<T> { [x, x] }
pub fn const3<T: Copy>(x: T) -> Vector3<T> { [x, x, x] }
pub fn const4<T: Copy>(x: T) -> Vector4<T> { [x, x, x, x] }

pub fn one2<T: Copy + NumCast>() -> Vector2<T> { cast2(const2(1)) }
pub fn one3<T: Copy + NumCast>() -> Vector3<T> { cast3(const3(1)) }
pub fn one4<T: Copy + NumCast>() -> Vector4<T> { cast4(const4(1)) }

pub fn cast2<T: NumCast + Copy, U: NumCast + Copy>(x: Point2<T>) -> Point2<U> { map2(x, cast) }
pub fn cast3<T: NumCast + Copy, U: NumCast + Copy>(x: Point3<T>) -> Point3<U> { map3(x, cast) }
pub fn cast4<T: NumCast + Copy, U: NumCast + Copy>(x: Point4<T>) -> Point4<U> { map4(x, cast) }
<|endoftext|>


<commit_before>//! Implement Norms for matrices

use lapack::fortran::*;
use num_traits::Zero;

pub trait ImplNorm: Sized {
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self;
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self;
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self;
}

macro_rules! impl_norm {
    ($scalar:ty, $lange:path) => {
impl ImplNorm for $scalar {
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        $lange(b'o', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = vec![Self::zero(); m];
        $lange(b'i', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        $lange(b'f', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
}
}} // end macro_rules

impl_norm!(f64, dlange);
impl_norm!(f32, slange);
<commit_msg>Use ColumnMajor (fixed) in norm_*<commit_after>//! Implement Norms for matrices

use lapack::c::*;

pub trait ImplNorm: Sized {
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self;
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self;
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self;
}

macro_rules! impl_norm {
    ($scalar:ty, $lange:path) => {
impl ImplNorm for $scalar {
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        $lange(Layout::ColumnMajor, b'o', m as i32, n as i32, &mut a, m as i32)
    }
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        $lange(Layout::ColumnMajor, b'i', m as i32, n as i32, &mut a, m as i32)
    }
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        $lange(Layout::ColumnMajor, b'f', m as i32, n as i32, &mut a, m as i32)
    }
}
}} // end macro_rules

impl_norm!(f64, dlange);
impl_norm!(f32, slange);
<|endoftext|>


<commit_before>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::thread;
//! # use std::time::Duration;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # thread::sleep(Duration::from_millis(5));
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));
                        });
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::thread;
/// # use std::time::Duration;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        // Mark the target stream as closed
                        let mut stream_core = stream_core.lock().unwrap();
                        stream_core.closed = true;
                        stream_core.notify.take().map(|notify| notify.notify());

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let mut stream_core = stream_core.lock().unwrap();

                    stream_core.pending.push_back(next_item);
                    stream_core.notify.take().map(|notify| notify.notify());
                });

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<commit_msg>Also don't need to use thread::sleep here either<commit_after>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));
                        });
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        // Mark the target stream as closed
                        let mut stream_core = stream_core.lock().unwrap();
                        stream_core.closed = true;
                        stream_core.notify.take().map(|notify| notify.notify());

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let mut stream_core = stream_core.lock().unwrap();

                    stream_core.pending.push_back(next_item);
                    stream_core.notify.take().map(|notify| notify.notify());
                });

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<|endoftext|>


<commit_before>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!

use super::desync::*;

use futures::*;
use futures::executor;

use std::mem;
use std::sync::*;
use std::thread;
use std::thread::JoinHandle;
use std::result::Result;
use std::collections::{HashMap, HashSet};

lazy_static! {
    /// The shared poll thread that's used to schedule events from pipe streams
    static ref POLL_THREAD: PollThread = PollThread::new();
}

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Poll the stream on the poll thread
    POLL_THREAD.monitor(move || {
        // Read from the stream and create a new reference to the callback function
        let next        = stream.poll();
        let process     = Arc::clone(&process);

        match next {
            // Just wait if the stream is not ready
            Ok(Async::NotReady) => true,

            // Stream returned a value
            Ok(Async::Ready(Some(next))) => {
                // Process the value on the stream
                desync.async(move |core| {
                    let mut process = process.lock().unwrap();
                    let process     = &mut *process;
                    process(core, Ok(next));
                });

                true
            },

            // Stream returned an error
            Err(e) => {
                // Process the error on the stream
                desync.async(move |core| {
                    let mut process = process.lock().unwrap();
                    let process     = &mut *process;
                    process(core, Err(e));
                });

                true
            },

            // Stream finished
            Ok(Async::Ready(None)) => false
        }
    });
}

/*
///
/// Pipes a stream into this object. Whenever an item becomes available on the strema, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> Box<dyn Stream<Item=Output, Error=OutputErr>>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     Send,
        OutputErr:  Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {
    unimplemented!()
}
*/

///
/// In order to implement the polling functions, we need a thread that runs the executor
/// for any streams that we're currently piping (calling pipe_in or pipe will effectively
/// need to spawn the relevant stream).
///
/// This represents that thread. There's a bit of a limitation in that the `poll` methods
/// for the various streams will block the thread so this may start to bottleneck at times of
/// high load or with streams with poll methods that take significant time to execute.
///
struct PollThread {
    /// The poll functions that are being monitored by this thread
    notifications: Arc<Mutex<PollNotifications>>,

    /// The function that should be called for every notification ID
    poll_functions: Arc<Mutex<HashMap<u32, Box<dyn FnMut() -> bool + Send>>>>,

    /// The joinhandle of the running thread
    thread: Arc<JoinHandle<()>>
}

///
/// Stores things being monitored
///
struct PollNotifications {
    /// Next available ID for a polling function
    next_id: u32,

    /// Poll functions where the notify handle has been set
    notified_ids: HashSet<u32>
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PollNotify {
    /// The ID that should be marked as notified when the callback is made
    id: u32,

    /// The structure where the notifications are stored
    notifications: Arc<Mutex<PollNotifications>>,

    /// The thread that should be notified when this notification occurs
    thread: thread::Thread
}

impl PollThread {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PollThread {
        // Create the monitors for the new thread
        let notifications = PollNotifications {
            next_id:        0,
            notified_ids:   HashSet::new()
        };
        let notifications = Arc::new(Mutex::new(notifications));

        // Create the set of polling functions
        let poll_functions = Arc::new(Mutex::new(HashMap::new()));

        // Run the thread with the monitors
        let thread = Self::run(Arc::clone(&notifications), Arc::clone(&poll_functions));
        let thread = Arc::new(thread);

        // Generate the thread object
        let thread = PollThread {
            notifications:  notifications,
            poll_functions: poll_functions,
            thread:         thread
        };

        thread
    }

    ///
    /// Starts the poll thread running (poll threads cannot currently be stopped)
    ///
    fn run(notifications: Arc<Mutex<PollNotifications>>, functions: Arc<Mutex<HashMap<u32, Box<dyn FnMut() -> bool + Send>>>>) -> JoinHandle<()> {
        thread::spawn(move || {
            loop {
                // Park the thread until there is something to do
                thread::park();

                // Fetch the list of notified functions we should call
                let to_notify = {
                    let mut notifications   = notifications.lock().unwrap();
                    let mut to_notify       = HashSet::new();

                    mem::swap(&mut to_notify, &mut notifications.notified_ids);

                    to_notify
                };

                // Notify each function in turn
                let mut functions   = functions.lock().unwrap();
                let thread          = thread::current();

                for function_id in to_notify {
                    // Fetch the function. If it returns false, we need to remove it from the list
                    let keep_function = functions.get_mut(&function_id)
                        .map(|poll_function| {
                            // Create the notification structure
                            let notify = PollNotify {
                                id:             function_id,
                                notifications:  Arc::clone(&notifications),
                                thread:         thread.clone()
                            };

                            // Call the polling function
                            executor::with_notify(&Arc::new(notify), 0, move || poll_function())
                        });

                    // If the function exists and returns false, then remove it from the set that we're polling
                    if keep_function == Some(false) {
                        functions.remove(&function_id);
                    }
                }
            }
        })
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> bool {
        let mut functions       = self.poll_functions.lock().unwrap();
        let mut notifications   = self.notifications.lock().unwrap();

        // Get an ID for this monitor
        let id = notifications.next_id;
        notifications.next_id += 1;

        // Store this item
        functions.insert(id, Box::new(poll_fn));

        // Mark it as notified
        notifications.notified_ids.insert(id);

        // Wake the thread
        self.thread.thread().unpark();
    }
}

impl executor::Notify for PollNotify {
    fn notify(&self, _id: usize) {
        // Add our ID to the notification list
        let mut notifications = self.notifications.lock().unwrap();
        notifications.notified_ids.insert(self.id);

        // Wake the thread
        self.thread.unpark();
    }
}
<commit_msg>Process piped instructions in a loop<commit_after>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!

use super::desync::*;

use futures::*;
use futures::executor;

use std::mem;
use std::sync::*;
use std::thread;
use std::thread::JoinHandle;
use std::result::Result;
use std::collections::{HashMap, HashSet};

lazy_static! {
    /// The shared poll thread that's used to schedule events from pipe streams
    static ref POLL_THREAD: PollThread = PollThread::new();
}

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Poll the stream on the poll thread
    POLL_THREAD.monitor(move || {
        loop {
            // Read the current status of the stream
            let process     = Arc::clone(&process);
            let next        = stream.poll();

            match next {
                // Just wait if the stream is not ready
                Ok(Async::NotReady) => { return true; },

                // Stream returned a value
                Ok(Async::Ready(Some(next))) => {
                    // Process the value on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Ok(next));
                    });
                },

                // Stream returned an error
                Err(e) => {
                    // Process the error on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Err(e));
                    });
                },

                // Stream finished
                Ok(Async::Ready(None)) => { return false; }
            }
        }
    });
}

/*
///
/// Pipes a stream into this object. Whenever an item becomes available on the strema, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> Box<dyn Stream<Item=Output, Error=OutputErr>>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     Send,
        OutputErr:  Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {
    unimplemented!()
}
*/

///
/// In order to implement the polling functions, we need a thread that runs the executor
/// for any streams that we're currently piping (calling pipe_in or pipe will effectively
/// need to spawn the relevant stream).
///
/// This represents that thread. There's a bit of a limitation in that the `poll` methods
/// for the various streams will block the thread so this may start to bottleneck at times of
/// high load or with streams with poll methods that take significant time to execute.
///
struct PollThread {
    /// The poll functions that are being monitored by this thread
    notifications: Arc<Mutex<PollNotifications>>,

    /// The function that should be called for every notification ID
    poll_functions: Arc<Mutex<HashMap<u32, Box<dyn FnMut() -> bool + Send>>>>,

    /// The joinhandle of the running thread
    thread: Arc<JoinHandle<()>>
}

///
/// Stores things being monitored
///
struct PollNotifications {
    /// Next available ID for a polling function
    next_id: u32,

    /// Poll functions where the notify handle has been set
    notified_ids: HashSet<u32>
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PollNotify {
    /// The ID that should be marked as notified when the callback is made
    id: u32,

    /// The structure where the notifications are stored
    notifications: Arc<Mutex<PollNotifications>>,

    /// The thread that should be notified when this notification occurs
    thread: thread::Thread
}

impl PollThread {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PollThread {
        // Create the monitors for the new thread
        let notifications = PollNotifications {
            next_id:        0,
            notified_ids:   HashSet::new()
        };
        let notifications = Arc::new(Mutex::new(notifications));

        // Create the set of polling functions
        let poll_functions = Arc::new(Mutex::new(HashMap::new()));

        // Run the thread with the monitors
        let thread = Self::run(Arc::clone(&notifications), Arc::clone(&poll_functions));
        let thread = Arc::new(thread);

        // Generate the thread object
        let thread = PollThread {
            notifications:  notifications,
            poll_functions: poll_functions,
            thread:         thread
        };

        thread
    }

    ///
    /// Starts the poll thread running (poll threads cannot currently be stopped)
    ///
    fn run(notifications: Arc<Mutex<PollNotifications>>, functions: Arc<Mutex<HashMap<u32, Box<dyn FnMut() -> bool + Send>>>>) -> JoinHandle<()> {
        thread::spawn(move || {
            loop {
                // Park the thread until there is something to do
                thread::park();

                // Fetch the list of notified functions we should call
                let to_notify = {
                    let mut notifications   = notifications.lock().unwrap();
                    let mut to_notify       = HashSet::new();

                    mem::swap(&mut to_notify, &mut notifications.notified_ids);

                    to_notify
                };

                // Notify each function in turn
                let mut functions   = functions.lock().unwrap();
                let thread          = thread::current();

                for function_id in to_notify {
                    // Fetch the function. If it returns false, we need to remove it from the list
                    let keep_function = functions.get_mut(&function_id)
                        .map(|poll_function| {
                            // Create the notification structure
                            let notify = PollNotify {
                                id:             function_id,
                                notifications:  Arc::clone(&notifications),
                                thread:         thread.clone()
                            };

                            // Call the polling function
                            executor::with_notify(&Arc::new(notify), 0, move || poll_function())
                        });

                    // If the function exists and returns false, then remove it from the set that we're polling
                    if keep_function == Some(false) {
                        functions.remove(&function_id);
                    }
                }
            }
        })
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> bool {
        let mut functions       = self.poll_functions.lock().unwrap();
        let mut notifications   = self.notifications.lock().unwrap();

        // Get an ID for this monitor
        let id = notifications.next_id;
        notifications.next_id += 1;

        // Store this item
        functions.insert(id, Box::new(poll_fn));

        // Mark it as notified
        notifications.notified_ids.insert(id);

        // Wake the thread
        self.thread.thread().unpark();
    }
}

impl executor::Notify for PollNotify {
    fn notify(&self, _id: usize) {
        // Add our ID to the notification list
        let mut notifications = self.notifications.lock().unwrap();
        notifications.notified_ids.insert(self.id);

        // Wake the thread
        self.thread.unpark();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use utils::{create_file, create_error};
use theme::Theme;
use tera::{Tera, Context};
use std::error::Error;
use pulldown_cmark::{html, Parser, Options, OPTION_ENABLE_TABLES};

pub struct Post {
    pub root: PathBuf,
    pub path: PathBuf,
    pub head: String,
    pub body: String,
    pub metadata: HashMap<String, String>,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Post {
        Post {
            root: root.as_ref().to_owned(),
            path: path.as_ref().to_owned(),
            head: String::new(),
            body: String::new(),
            metadata: HashMap::new(),
        }
    }

    pub fn dest(&self) -> PathBuf {
        self.root.join("builds").join(self.path.with_extension("html"))
    }

    pub fn content(&self) -> String {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        let mut s = String::with_capacity(self.body.len() * 3 / 2);
        let p = Parser::new_ext(&self.body, opts);
        html::push_html(&mut s, p);
        s
    }

    pub fn tags(&self) -> Vec<&str> {
        if let Some(tag_str) = self.metadata.get("tags") {
            tag_str.split(',').map(|x| x.trim()).filter(|x| x.len() != 0).collect()
        } else {
            Vec::new()
        }
    }

    pub fn load(&mut self) -> ::std::io::Result<()> {
        debug!("loading post: {}", self.path.display());
        let mut pf = File::open(self.root.join(&self.path))?;
        let mut content = String::new();
        pf.read_to_string(&mut content)?;
        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return create_error(format!("post({path}) must both have `head` and `body` parts",
                                        path=self.path.display()));
        }
        self.head = v[0].to_string();
        self.body = v[1].to_string();
        for line in self.head.lines() {
            let pair: Vec<&str> = line.splitn(2, ':').collect();
            if pair.len() != 2 {
                return create_error(format!("post({path}) `head` part parse error: {line}",
                                            path=self.path.display(),
                                            line=line));
            }
            self.metadata.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
        Ok(())
    }

    pub fn render_html(&self, tera: &Tera) -> ::std::io::Result<()> {
        debug!("rendering post: {}", self.path.display());
        let dest = self.dest();
        let mut f = create_file(&dest)?;
        let mut context = Context::new();
        let content = self.content();
        context.add("content", &content);
        match tera.render("post.tpl", context) {
            Ok(s) => {
                f.write(s.as_bytes())?;
                debug!("created html: {:?}", dest.display());
                return Ok(());
            }
            Err(e) => {
                return create_error(format!("post({path}) render error: {descrition}",
                                            path=self.path.display(),
                                            descrition=e.description()));
            }
        }
    }
}
<commit_msg>post.src<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use utils::{create_file, create_error};
use theme::Theme;
use tera::{Tera, Context};
use std::error::Error;
use pulldown_cmark::{html, Parser, Options, OPTION_ENABLE_TABLES};

pub struct Post {
    pub root: PathBuf,
    pub path: PathBuf,
    pub head: String,
    pub body: String,
    pub metadata: HashMap<String, String>,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Post {
        Post {
            root: root.as_ref().to_owned(),
            path: path.as_ref().to_owned(),
            head: String::new(),
            body: String::new(),
            metadata: HashMap::new(),
        }
    }

    pub fn src(&self) -> PathBuf {
        self.root.join(&self.path)
    }

    pub fn dest(&self) -> PathBuf {
        self.root.join("builds").join(self.path.with_extension("html"))
    }

    pub fn content(&self) -> String {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        let mut s = String::with_capacity(self.body.len() * 3 / 2);
        let p = Parser::new_ext(&self.body, opts);
        html::push_html(&mut s, p);
        s
    }

    pub fn tags(&self) -> Vec<&str> {
        if let Some(tag_str) = self.metadata.get("tags") {
            tag_str.split(',').map(|x| x.trim()).filter(|x| x.len() != 0).collect()
        } else {
            Vec::new()
        }
    }

    pub fn load(&mut self) -> ::std::io::Result<()> {
        debug!("loading post: {}", self.path.display());
        let mut pf = File::open(self.src())?;
        let mut content = String::new();
        pf.read_to_string(&mut content)?;
        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return create_error(format!("post({path}) must both have `head` and `body` parts",
                                        path=self.path.display()));
        }
        self.head = v[0].to_string();
        self.body = v[1].to_string();
        for line in self.head.lines() {
            let pair: Vec<&str> = line.splitn(2, ':').collect();
            if pair.len() != 2 {
                return create_error(format!("post({path}) `head` part parse error: {line}",
                                            path=self.path.display(),
                                            line=line));
            }
            self.metadata.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
        Ok(())
    }

    pub fn render_html(&self, tera: &Tera) -> ::std::io::Result<()> {
        debug!("rendering post: {}", self.path.display());
        let dest = self.dest();
        let mut f = create_file(&dest)?;
        let mut context = Context::new();
        let content = self.content();
        context.add("content", &content);
        match tera.render("post.tpl", context) {
            Ok(s) => {
                f.write(s.as_bytes())?;
                debug!("created html: {:?}", dest.display());
                return Ok(());
            }
            Err(e) => {
                return create_error(format!("post({path}) render error: {descrition}",
                                            path=self.path.display(),
                                            descrition=e.description()));
            }
        }
    }
}
<|endoftext|>