<commit_before>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(default_type_params)]
#[macro_use] extern crate log;

extern crate smtp;
extern crate getopts;

use std::old_io::stdin;
use std::string::String;
use std::old_io::net::ip::Port;
use std::os;
use getopts::{optopt, optflag, getopts, OptGroup, usage};

use smtp::client::Client;
use smtp::error::SmtpResult;
use smtp::mailer::Email;

fn sendmail(source_address: &str, recipient_addresses: &[&str], message: &str, subject: &str,
        server: &str, port: Port, my_hostname: &str) -> SmtpResult {

    let mut email = Email::new();
    for destination in recipient_addresses.iter() {
        email.to(*destination);
    }
    email.from(source_address);
    email.body(message);
    email.subject(subject);
    email.date_now();

    let mut client: Client = Client::new((server, port));
    client.set_hello_name(my_hostname);
    client.send(email)
}

fn print_usage(description: String, _opts: &[OptGroup]) {
    println!("{}", usage(description.as_slice(), _opts));
}

fn main() {
    let args = os::args();

    let mut args_string = Vec::new();
    for arg in args.iter() {
        args_string.push(arg.clone());
    };

    let program = args[0].clone();
    let description = format!("Usage: {0} [options...] recipients\n\n\
                               This program reads a message on standard input until it reaches\
                               EOF, then tries to send it using the given paramters.\n\n\
                               Example: {0} -r user@example.org user@example.com < message.txt",
                              program);

    let opts = [
        optopt("s", "subject", "set the email subject", "SUBJECT"),
        optopt("r", "reverse-path", "set the sender address", "FROM_ADDRESS"),
        optopt("p", "port", "set the port to use, default is 25", "PORT"),
        optopt("a", "server", "set the server to use, default is localhost", "SERVER"),
        optopt("m", "my-hostname", "set the hostname used by the client", "MY_HOSTNAME"),
        optflag("h", "help", "print this help menu"),
    ];

    let matches = match getopts(args_string.tail(), &opts) {
        Ok(m) => m,
        Err(f) => panic!("{}", f),
    };

    if matches.opt_present("h") {
        print_usage(description, &opts);
        return;
    }

    if !matches.opt_present("r") {
        println!("The sender option is required");
        print_usage(program, &opts);
        return;
    }

    let recipients_str: &str = if !matches.free.is_empty() {
        matches.free[0].as_slice()
    } else {
        print_usage(description, &opts);
        return;
    };

    let mut recipients = Vec::new();
    for recipient in recipients_str.split(' ') {
        recipients.push(recipient);
    }

    let mut message = String::new();

    let mut line = stdin().read_line();
    while line.is_ok() {
        message.push_str(line.unwrap().as_slice());
        line = stdin().read_line();
    }

    match sendmail(
        // sender
        matches.opt_str("r").unwrap().as_slice(),
        // recipients
        recipients.as_slice(),
        // message content
        message.as_slice(),
        // subject
        match matches.opt_str("s") {
            Some(ref subject) => subject.as_slice(),
            None => "(empty subject)"
        },
        // server
        match matches.opt_str("a") {
            Some(ref server) => server.as_slice(),
            None => "localhost"
        },
        // port
        match matches.opt_str("p") {
            Some(port) => port.as_slice().parse::<Port>().unwrap(),
            None => 25
        },
        // my hostname
        match matches.opt_str("m") {
            Some(ref my_hostname) => my_hostname.as_slice(),
            None => "localhost"
        },
    )
    {
        Ok(..) => info!("Email sent successfully"),
        Err(error) => error!("{}", error),
    }
}
<commit_msg>Add features to silent warnings<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(core, old_io, rustc_private, os, collections)]
#[macro_use] extern crate log;

extern crate smtp;
extern crate getopts;

use std::old_io::stdin;
use std::old_io::net::ip::Port;
use std::string::String;
use std::os;
use getopts::{optopt, optflag, getopts, OptGroup, usage};

use smtp::client::Client;
use smtp::error::SmtpResult;
use smtp::mailer::Email;

fn sendmail(source_address: &str, recipient_addresses: &[&str], message: &str, subject: &str,
        server: &str, port: Port, my_hostname: &str) -> SmtpResult {

    let mut email = Email::new();
    for destination in recipient_addresses.iter() {
        email.to(*destination);
    }
    email.from(source_address);
    email.body(message);
    email.subject(subject);
    email.date_now();

    let mut client: Client = Client::new((server, port));
    client.set_hello_name(my_hostname);
    client.send(email)
}

fn print_usage(description: String, _opts: &[OptGroup]) {
    println!("{}", usage(description.as_slice(), _opts));
}

fn main() {
    let args = os::args();

    let mut args_string = Vec::new();
    for arg in args.iter() {
        args_string.push(arg.clone());
    };

    let program = args[0].clone();
    let description = format!("Usage: {0} [options...] recipients\n\n\
                               This program reads a message on standard input until it reaches\
                               EOF, then tries to send it using the given paramters.\n\n\
                               Example: {0} -r user@example.org user@example.com < message.txt",
                              program);

    let opts = [
        optopt("s", "subject", "set the email subject", "SUBJECT"),
        optopt("r", "reverse-path", "set the sender address", "FROM_ADDRESS"),
        optopt("p", "port", "set the port to use, default is 25", "PORT"),
        optopt("a", "server", "set the server to use, default is localhost", "SERVER"),
        optopt("m", "my-hostname", "set the hostname used by the client", "MY_HOSTNAME"),
        optflag("h", "help", "print this help menu"),
    ];

    let matches = match getopts(args_string.tail(), &opts) {
        Ok(m) => m,
        Err(f) => panic!("{}", f),
    };

    if matches.opt_present("h") {
        print_usage(description, &opts);
        return;
    }

    if !matches.opt_present("r") {
        println!("The sender option is required");
        print_usage(program, &opts);
        return;
    }

    let recipients_str: &str = if !matches.free.is_empty() {
        matches.free[0].as_slice()
    } else {
        print_usage(description, &opts);
        return;
    };

    let mut recipients = Vec::new();
    for recipient in recipients_str.split(' ') {
        recipients.push(recipient);
    }

    let mut message = String::new();

    let mut line = stdin().read_line();
    while line.is_ok() {
        message.push_str(line.unwrap().as_slice());
        line = stdin().read_line();
    }

    match sendmail(
        // sender
        matches.opt_str("r").unwrap().as_slice(),
        // recipients
        recipients.as_slice(),
        // message content
        message.as_slice(),
        // subject
        match matches.opt_str("s") {
            Some(ref subject) => subject.as_slice(),
            None => "(empty subject)"
        },
        // server
        match matches.opt_str("a") {
            Some(ref server) => server.as_slice(),
            None => "localhost"
        },
        // port
        match matches.opt_str("p") {
            Some(port) => port.as_slice().parse::<Port>().unwrap(),
            None => 25
        },
        // my hostname
        match matches.opt_str("m") {
            Some(ref my_hostname) => my_hostname.as_slice(),
            None => "localhost"
        },
    )
    {
        Ok(..) => info!("Email sent successfully"),
        Err(error) => error!("{}", error),
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(core)]

extern crate readline as rl;
extern crate libc;

use std::io::{BufRead,BufReader};
use std::fs::File;
use std::path::Path;
use std::ffi::CStr;
use std::str;

fn complete(text: String) -> Vec<String> {
    let path = Path::new("/usr/share/dict/words");
    let file = BufReader::new(File::open(&path).unwrap());
    let mut entries: Vec<String> = Vec::new();
    for line in file.lines() {
        let word = line.unwrap();
        if (&word).starts_with(&text) {
            entries.push(word);
        }
    }
    return entries;
}

extern fn rl_compentry_func(text: *const i8, state: i32) -> *const i8 {
    if state == 0 {
        let txt = unsafe { CStr::from_ptr(text).to_bytes() };
        let entries = complete(str::from_utf8(txt).unwrap().to_string());
        rl::set_compentries(entries);
    }
    rl::get_compentry(state as usize)
}

extern fn my_attempted_completion_function(text: *const i8, _start: i32, _end: i32) -> *mut *const i8 {
    return rl::rl_completion_matches(text, rl_compentry_func)
}

// cargo run --example simple
pub fn main() {
    rl::rl_initialize().unwrap();
    //println!("{}", rl::rl_readline_version())
    println!("{}", rl::rl_library_version());

    rl::set_rl_attempted_completion_function(Some(my_attempted_completion_function));

    loop {
        match rl::readline("> ") {
            Some(line) => {
                let l = line.as_ref();
                rl::add_history(l);
                println!("{}", l);
                //println!("{}", rl::history_get(-2));
            },
            _ => {
                println!("");
                break
            }
        }
    }
}<commit_msg>Misc.<commit_after>#![feature(libc)]

extern crate readline as rl;
extern crate libc;

use std::io::{BufRead,BufReader};
use std::fs::File;
use std::path::Path;
use std::ffi::CStr;
use std::str;

fn complete(text: String) -> Vec<String> {
    let path = Path::new("/usr/share/dict/words");
    let file = BufReader::new(File::open(&path).unwrap());
    let mut entries: Vec<String> = Vec::new();
    for line in file.lines() {
        let word = line.unwrap();
        if (&word).starts_with(&text) {
            entries.push(word);
        }
    }
    return entries;
}

extern fn rl_compentry_func(text: *const i8, state: i32) -> *const i8 {
    if state == 0 {
        let txt = unsafe { CStr::from_ptr(text).to_bytes() };
        let entries = complete(str::from_utf8(txt).unwrap().to_string());
        rl::set_compentries(entries);
    }
    rl::get_compentry(state as usize)
}

extern fn my_attempted_completion_function(text: *const i8, _start: i32, _end: i32) -> *mut *const i8 {
    return rl::rl_completion_matches(text, rl_compentry_func)
}

// cargo run --example simple
pub fn main() {
    rl::rl_initialize().unwrap();
    //println!("{}", rl::rl_readline_version())
    println!("{}", rl::rl_library_version());

    rl::set_rl_attempted_completion_function(Some(my_attempted_completion_function));

    loop {
        match rl::readline("> ") {
            Some(line) => {
                let l = line.as_ref();
                rl::add_history(l);
                println!("{}", l);
                //println!("{}", rl::history_get(-2));
            },
            _ => {
                println!("");
                break
            }
        }
    }
}<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, RenderFrame};
use polydraw::draw::{RGB, bresenham};
use polydraw::geom::point::Point;
use polydraw::geom::polygon::Polygon;

struct PolygonRenderer {
   polygon: Polygon,
}

impl PolygonRenderer {
   fn new() -> Self {
      let mult = 50;
      let polygon = Polygon::new(vec![
         Point::new(2 * mult, 9 * mult),
         Point::new(13 * mult, 12 * mult),
         Point::new(9 * mult, 3 * mult),
         Point::new(7 * mult, 2 * mult),
      ]);

      PolygonRenderer {
         polygon: polygon
      }
   }
}

impl Renderer for PolygonRenderer {
   fn render(&mut self, frame: &mut RenderFrame) {
      frame.clear();

      let color = RGB::new(127, 223, 255);

      let mut prev = self.polygon.points[self.polygon.points.len() - 1];

      for point in &self.polygon.points {
         bresenham(frame, prev.x as i32, prev.y as i32, point.x as i32, point.y as i32, &color);
         prev = point.clone();
      }
   }
}

fn main() {
   let mut renderer = PolygonRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Polygon")
      .run();
}
<commit_msg>Printing all the points in the polygon example and point ordering function<commit_after>extern crate polydraw;

use std::cmp::Ordering;

use polydraw::{Application, Renderer, RenderFrame};
use polydraw::draw::{RGB, bresenham};
use polydraw::geom::point::Point;
use polydraw::geom::polygon::Polygon;

struct PolygonRenderer {
   polygon: Polygon,
}

impl PolygonRenderer {
   fn new() -> Self {
      let mult = 50;
      let mut polygon = Polygon::new(vec![
         Point::new(2 * mult, 9 * mult),
         Point::new(13 * mult, 12 * mult),
         Point::new(9 * mult, 3 * mult),
         Point::new(7 * mult, 2 * mult),
      ]);

      PolygonRenderer {
         polygon: polygon
      }
   }

   fn printall(&self) {
      let mut prev = self.polygon.points[self.polygon.points.len() - 1];

      for point in &self.polygon.points {
         if cmp_points(&prev, &point) == Ordering::Less {
            println!("{} {} - {} {}", prev.x, prev.y, point.x, point.y);
         } else {
            println!("{} {} - {} {}", point.x, point.y, prev.x, prev.y);
         }
         prev = point.clone();
      }
   }
}

impl Renderer for PolygonRenderer {
   fn render(&mut self, frame: &mut RenderFrame) {
      frame.clear();

      let color = RGB::new(127, 223, 255);

      let mut prev = self.polygon.points[self.polygon.points.len() - 1];

      for point in &self.polygon.points {
         bresenham(frame, prev.x as i32, prev.y as i32, point.x as i32, point.y as i32, &color);
         prev = point.clone();
      }
   }
}

fn cmp_points(pt1: &Point, pt2: &Point) -> Ordering {
   if pt1.y < pt2.y {
      Ordering::Less
   } else if pt1.y > pt2.y {
      Ordering::Greater
   } else if pt1.x < pt2.x {
      Ordering::Less
   } else if pt1.x > pt2.x {
      Ordering::Greater
   } else {
      Ordering::Equal
   }
}

fn main() {
   let mut renderer = PolygonRenderer::new();

   renderer.printall();

   Application::new()
      .renderer(&mut renderer)
      .title("Polygon")
      .run();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate fern;
extern crate time;
extern crate gpredict;

use gpredict::tle;
use gpredict::predict::{Predict, Location};

use std::thread;

fn conf_logger() {
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}

fn main() {
    // setup fern logger
    conf_logger();

    // start processing
    info!("predict example started");

    let tle: tle::Tle = tle::Tle{
        name: "ESTCUBE 1".to_string(),
        line1: "1 39161U 13021C   15091.47675532  .00001890  00000-0  31643-3 0  9990".to_string(),
        line2: "2 39161  98.0727 175.0786 0009451 192.0216 168.0788 14.70951130101965".to_string()
    };

    let location: Location = Location{lat_deg:58.64560, lon_deg: 23.15163, alt_m: 8};
    let mut predict: Predict = Predict::new(&tle, &location);

    loop {
        predict.update(Some(time::now_utc()));
        info!("aos        : {:?}", predict.sat.aos.expect("do not have AOS with this satellite"));
        info!("los        : {:?}", predict.sat.los.expect("do not have LOS with this satellite"));
        info!("az         : {:.2}°", predict.sat.az_deg);
        info!("el         : {:.2}°", predict.sat.el_deg);
        info!("range      : {:.0} km", predict.sat.range_km);
        info!("range rate : {:.3} km/sec\n", predict.sat.range_rate_km_sec);

        thread::sleep_ms(1000);
    }
}
<commit_msg>use grifex as example<commit_after>#[macro_use]
extern crate log;
extern crate fern;
extern crate time;
extern crate gpredict;

use gpredict::tle;
use gpredict::predict::{self, Predict, Location};

use std::thread;

fn conf_logger() {
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}

fn main() {
    // setup fern logger
    conf_logger();

    // start processing
    info!("predict example started");

    let tle: tle::Tle = tle::Tle{
        name: "GRIFEX".to_string(),
        line1: "1 40379U 15003D   15243.42702278  .00003367  00000-0  17130-3 0  9993".to_string(),
        line2: "2 40379  99.1124 290.6779 0157088   8.9691 351.4280 15.07659299 31889".to_string()
    };

    let location: Location = Location{lat_deg:58.64560, lon_deg: 23.15163, alt_m: 8};
    let mut predict: Predict = Predict::new(&tle, &location);

    loop {
        // these two are the same:
        //predict.update(Some(time::now_utc()));
        predict.update(None);

        info!("aos        : {:}", predict.sat.aos.expect("do not have AOS with this satellite").to_utc().rfc3339());
        info!("los        : {:}", predict.sat.los.expect("do not have LOS with this satellite").to_utc().rfc3339());
        info!("az         : {:.2}°", predict.sat.az_deg);
        info!("el         : {:.2}°", predict.sat.el_deg);
        info!("range      : {:.0} km", predict.sat.range_km);
        info!("range rate : {:.3} km/sec\n", predict.sat.range_rate_km_sec);

        thread::sleep_ms(1000);
    }
}
<|endoftext|>


<commit_before>extern crate rusttype;
use rusttype::*;
fn main() {
    use std::io::Write;
    let font_data = include_bytes!("Gudea-Regular.ttf");
    let collection = FontCollection::<'static>::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap(); // only succeeds if collection consists of one font
    {
        let height: f32 = 20.1; // to get 80 chars across (fits most terminals); adjust as desired
        let pixel_height = height.ceil() as usize;
        let scale = PixelsXY(height*2.0, height);
        let v_metrics = font.v_metrics(scale);
        let offset = point(0.0, v_metrics.ascent);
        // 2x scale in x direction to counter the aspect ratio of monospace characters.
        let to_draw: Vec<_> = font.layout("Hello!", PixelsXY(height*2.0, height), offset).collect();
        // Finds the most visually pleasing width to display
        let width = to_draw.iter().map(|g| g.h_metrics().advance_width).fold(0.0, |x, y| x + y).ceil() as usize;
        println!("width: {}, height: {}", width, pixel_height);
        // Rasterise directly into ASCII art.
        let mut data = vec![b'@'; width * pixel_height];
        let mapping = b"@%#x+=:-. "; // The approximation of greyscale
        let mapping_scale = (mapping.len()-1) as f32;
        for g in to_draw {
            if let Some(bb) = g.pixel_bounding_box() {
                g.draw(|x, y, v| {
                    let i = (v*mapping_scale + 0.5) as usize;
                    // Something's wrong if you get $ in the output.
                    let c = mapping.get(i).cloned().unwrap_or(b'$');
                    let x = (x as i32 + bb.min.x) as usize;
                    let y = (y as i32 + bb.min.y) as usize;
                    data[(x + y * width)] = c;
                })
            }
        }
        // Print it out
        let stdout = ::std::io::stdout();
        let mut handle = stdout.lock();
        for j in 0..pixel_height {
            handle.write(&data[j*width..(j+1)*width]).unwrap();
            handle.write(b"\n").unwrap();
        }
    }
}
<commit_msg>Slightly tweaked example.<commit_after>extern crate rusttype;
use rusttype::*;
fn main() {
    use std::io::Write;
    let font_data = include_bytes!("Gudea-Regular.ttf");
    let collection = FontCollection::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap(); // only succeeds if collection consists of one font
    {
        let height: f32 = 20.1; // to get 80 chars across (fits most terminals); adjust as desired
        let pixel_height = height.ceil() as usize;
        // 2x scale in x direction to counter the aspect ratio of monospace characters.
        let scale = PixelsXY(height*2.0, height);
        let v_metrics = font.v_metrics(scale);
        let offset = point(0.0, v_metrics.ascent);
        let to_draw: Vec<_> = font.layout("Hello!", scale, offset).collect();
        // Finds the most visually pleasing width to display
        let width = to_draw.iter().map(|g| g.h_metrics().advance_width)
            .fold(0.0, |x, y| x + y).ceil() as usize;
        println!("width: {}, height: {}", width, pixel_height);
        // Rasterise directly into ASCII art.
        let mut data = vec![b'@'; width * pixel_height];
        let mapping = b"@%#x+=:-. "; // The approximation of greyscale
        let mapping_scale = (mapping.len()-1) as f32;
        for g in to_draw {
            if let Some(bb) = g.pixel_bounding_box() {
                g.draw(|x, y, v| {
                    let i = (v*mapping_scale + 0.5) as usize;
                    // Something's wrong if you get $ in the output.
                    let c = mapping.get(i).cloned().unwrap_or(b'$');
                    let x = (x as i32 + bb.min.x) as usize;
                    let y = (y as i32 + bb.min.y) as usize;
                    data[(x + y * width)] = c;
                })
            }
        }
        // Print it out
        let stdout = ::std::io::stdout();
        let mut handle = stdout.lock();
        for j in 0..pixel_height {
            handle.write(&data[j*width..(j+1)*width]).unwrap();
            handle.write(b"\n").unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate syntect;
use std::path::Path;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{Theme, ThemeSet, Style};
use syntect::util::as_24_bit_terminal_escaped;
use syntect::easy::HighlightFile;
use syntect::dumps::{from_dump_file, dump_to_file};

use std::io::BufRead;

fn load_theme(tm_file: &String) -> Theme {
    let tm_path = Path::new(tm_file);
    let tm_cache = tm_path.with_extension("themedump");

    if tm_cache.exists() {
        from_dump_file(tm_cache).unwrap()
    } else {
        let theme = ThemeSet::get_theme(tm_path).unwrap();
        dump_to_file(&theme, tm_cache).unwrap();
        theme

    }
}

fn main() {
    let ss = SyntaxSet::load_defaults_newlines(); // note we load the version with newlines
    let ts = ThemeSet::load_defaults();

    let args: Vec<String> = std::env::args().collect();
    let src;
    let theme;
    let theme_ref;

    if args.len() < 2 {
        println!("USAGE: ./syncat [THEME_FILE] SRC_FILE");
        return;
    } else if args.len() == 2 {
        theme_ref = &ts.themes["base16-ocean.dark"];
        src = &args[1];
    } else {
        theme = load_theme(&args[1]);
        theme_ref = &theme;
        src = &args[2];
    }

    let mut highlighter = HighlightFile::new(src, &ss, theme_ref).unwrap();

    // We use read_line instead of `for line in highlighter.reader.lines()` because that
    // doesn't return strings with a `\n`, and including the `\n` gets us more robust highlighting.
    // See the documentation for `SyntaxSet::load_syntaxes`.
    // It also allows re-using the line buffer, which should be a tiny bit faster.
    let mut line = String::new();
    while highlighter.reader.read_line(&mut line).unwrap() > 0 {
        {
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line);
            print!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
        line.clear();
    }
}
<commit_msg>syncat: Added --list-file-types<commit_after>extern crate syntect;
use std::path::Path;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{Theme, ThemeSet, Style};
use syntect::util::as_24_bit_terminal_escaped;
use syntect::easy::HighlightFile;
use syntect::dumps::{from_dump_file, dump_to_file};

use std::io::BufRead;

fn load_theme(tm_file: &String) -> Theme {
    let tm_path = Path::new(tm_file);
    let tm_cache = tm_path.with_extension("themedump");

    if tm_cache.exists() {
        from_dump_file(tm_cache).unwrap()
    } else {
        let theme = ThemeSet::get_theme(tm_path).unwrap();
        dump_to_file(&theme, tm_cache).unwrap();
        theme

    }
}

fn main() {
    let ss = SyntaxSet::load_defaults_newlines(); // note we load the version with newlines
    let ts = ThemeSet::load_defaults();

    let args: Vec<String> = std::env::args().collect();
    let src;
    let theme;
    let theme_ref;

    if args.len() < 2 {
        println!("USAGE: ./syncat [THEME_FILE] SRC_FILE");
        println!("       ./syncat --list-file-types");
        return;

    } else if args.len() > 1 && args[1] == "--list-file-types" {
        println!("Supported file types:");

        for sd in ss.syntaxes() {
            println!("- {} (.{})", sd.name, sd.file_extensions.join(", ."));
        }

        return;

    } else if args.len() == 2 {
        theme_ref = &ts.themes["base16-ocean.dark"];
        src = &args[1];

    } else {
        theme = load_theme(&args[1]);
        theme_ref = &theme;
        src = &args[2];
    }

    let mut highlighter = HighlightFile::new(src, &ss, theme_ref).unwrap();

    // We use read_line instead of `for line in highlighter.reader.lines()` because that
    // doesn't return strings with a `\n`, and including the `\n` gets us more robust highlighting.
    // See the documentation for `SyntaxSet::load_syntaxes`.
    // It also allows re-using the line buffer, which should be a tiny bit faster.
    let mut line = String::new();
    while highlighter.reader.read_line(&mut line).unwrap() > 0 {
        {
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line);
            print!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
        line.clear();
    }
}
<|endoftext|>


<commit_before>/// In addition to implementing these traits, a StewardData must have Eq be equivalent to the quality of its serialization, and invariant under cloning and serialize-deserialize cycles.
trait StewardData: Any + Send + Sync + Clone + Eq + Serialize + Deserialize + Debug {

}

trait TimeStewardModificationReverter {
  fn revert (event: ?????)->invalidated stuff etc., like the return value of the original modify functions;
}

/*

Loosely speaking, these must be retroactive data structures. Specifically, I'll call them **stack-retroactive data structures**. They are like fully retroactive data structures, except that operations in the past are also permitted to delete arbitrary subsets of the existing operations that are later in time.

They must obey these conditions:
* The result of a query from a non-snapshot accessor must depend only on the initial snapshot and currently existing operations, and not, for instance, on the order the operations were added. It must also be invariant under taking snapshots at earlier historical times and restoring from them.
* The results of a query/snapshot from a *snapshot accessor* must depend only on the initial snapshot and operations that existed *at the time the snapshot accessor was created*. (In order to maintain this condition, the structure may have to examine its StewardHandle.snapshots() during insert_operation().) This condition may be violated if forget_snapshot() has been called for that snapshot.
* If a change to the operations would change the result of an earlier query (earlier in program time, >= in historical time), and that earlier query submitted a InvalidationHandle, that update operation must invalidate it by including the InvalidationHandle in its return value. (False-positives are permitted, though undesirable). It need only return each InvalidationHandle once.
* Any method called at a historical time > self.valid_since() must return Ok. self.valid_since() must be TheBeginning when a with_steward() is created, and After (time) when a from_snapshot() is created. It must not increase except from calls to discard_before or insert_operation, and if it implements FullTimeStewardDataThingy, it must not increase from calls to insert_operation either.

They also *should* obey these conditions:
* whenever the structure stores obsolete information to maintain a snapshot, it should notify the snapshot using snapshot.????? so that the snapshot may free up the memory using forget_snapshot() when it is dropped.

*/
struct QueryResult <Whatever: TimeStewardDataThingy> {
  data: Whatever::QueryResultData;
  valid_until: something < ExtendedTime <Whatever::Steward::Basics>>;
}
trait TimeStewardDataThingy {

  type Steward: TimeSteward;

  // All inputs are required to have a standard format, so that the structure can be audited.
  type Query: StewardData;
  type QueryResultData: StewardData;
  type Operation: StewardData;
  type Snapshot: StewardData;

  fn with_steward (steward: StewardHandle <Self::Steward>)->Self;
  fn from_snapshot (steward: StewardHandle <Self::Steward>, snapshot: &Self::Snapshot)->Self;

  fn query <A: Accessor> (&self, query: Self::Query, accessor: A)->Result <QueryResult<Self>,>;

  fn snapshot (snapshot: Self::Steward::Snapshot)->Snapshot;
  /// requires a &Steward only so that you can't do it in a predictor or event function.
  //Maybe this should also return a range of times changed so you know what snapshots need to be taken?
  fn insert_operation (&mut self, time: ExtendedTime <Self::Steward::Basics>, operation: Self::Operation, & Steward)->Result <,>;

  fn valid_since (&self, & Steward)->ValidSince <ExtendedTime <Self::Steward::Basics>>;
  fn forget_before (&mut self, time: ExtendedTime <Self::Steward::Basics>, & Steward);
  fn forget_snapshot (&mut self, StewardRc <Steward::Snapshot>);

  // query functions, which take an accessor and possibly a prediction handle, which may be stored in self for future invalidation
  // modify functions, which take a mutator and
  // - possibly return invalidated prediction handles
  // – possibly return spawned predictions, as from creating a new entity
  // - assuming this is for a full TimeSteward, return a StewardRc <TimeStewardModificationReverter> (which, for the simple case, may be a Self). This makes each potential reversion take at least a fat-pointer to store, unless we can make StewardRc be a thin pointer with the vtable at the destination.
}

#[derive (Clone)]
struct StewardHandle <Steward: TimeSteward> {

}
impl <Steward: TimeSteward> StewardHandle <Steward> {
  fn snapshots (&self)->& SnapshotTree <Steward>;
}
impl <Steward: TimeSteward> SnapshotTree <Steward> {
  fn iterate_snapshots (time_range, since_snapshot_number)->impl Iter<Item = (&Steward::Basics::Time, &StewardRc <Steward::Snapshot>)>;
}

trait EntityHistory {
  type Steward: Steward;
  fn get (m: & Steward::Mutator) {
}
struct TypedEntityHistory<E:Entity, S: Steward> {
  data: Steward::EntityHistory;
}
impl TypedEntityHistory {
  fn get (m: & S::Mutator) {self.data.get (m).downcast_ref().expect()}
}

trait Entity {
  type Varying = Self;
  type Constants = ();
}

trait Mutator : ??? + Rng {
  type Steward: Steward;
  fn create <E: Entity> (&mut self, constants: E::Constants)->TypedEntityHistory <E, B::S>;
  fn get <E: Entity> (&self, t: TypedEntityHistory <E, B::S>)->E::Varying {t.data.get (...).downcast_ref().expect()}
  ;
}

trait Steward {
  type Mutator: Mutator <Steward = Self>;
  type EntityHistory: EntityHistory <Steward = Self>;
}

impl Event for Struct {
  ...
  fn call <M: Mutator <...>> (& self, mutator: M) {
    let history: TypedEntityHistory <MyType, M::Steward> = self.entity_history;
    let value: &MyType = history.get (mutator);

    let new_history = mutator.create <MyType>(constants);
  }
}

<commit_msg>More work on the new API<commit_after>/// Data used for a TimeSteward simulation, such as times, entities, and events.
///
/// TimeSteward has strong requirements for serializability. In addition to implementing these traits, a StewardData must have Eq be equivalent to equality of its serialization, and invariant under cloning and serialize-deserialize cycles.
pub trait StewardData: Any + Send + Sync + Clone + Eq + Serialize + Deserialize + Debug {}

trait TimeStewardModificationReverter {
  fn revert (event: ?????)->invalidated stuff etc., like the return value of the original modify functions;
}

/**

Loosely speaking, these must be retroactive data structures.

Specifically, I'll call them **stack-retroactive data structures**. They are like fully retroactive data structures, except that operations in the past are also permitted to delete arbitrary subsets of the existing operations that are later in time. This leniency is because:
* Data structures can be more efficient if they don't have to support insertion or deletion in the middle, and
* In many cases, the later operations would almost certainly be invalidated anyway if the earlier one was invalidated.

They must obey these conditions:
* The result of a query from a non-snapshot accessor must depend only on the initial snapshot and currently existing operations, and not, for instance, on the order the operations were added. It must also be invariant under taking snapshots at earlier historical times and restoring from them.
* Also, the existing predictors are implicit in the current state. They may not change over serializing and deserializing through a snapshot.
* The results of a query/snapshot from a *snapshot accessor* must depend only on the initial snapshot and operations that existed *at the time the snapshot accessor was created*. (In order to maintain this condition, the structure may have to examine its StewardHandle.snapshots() during insert_operation().) This condition may be violated if forget_snapshot() has been called for that snapshot.
* If a change to the operations would change the result of an earlier query (earlier in program time, >= in historical time), and that earlier query submitted a InvalidationHandle, that update operation must invalidate it by including an equal InvalidationHandle in its return value. (False-positives are permitted, though undesirable). It need only return each InvalidationHandle once. Note that it does NOT have to retain copies of every handle submitted, if it has some way of looking them up, for example by querying other DataTimelines.
* Any method called at a historical time > self.valid_since() must return Ok. self.valid_since() must be TheBeginning when a with_steward() is created, and After (time) when a from_snapshot() is created. It must not increase except from calls to discard_before or insert_operation, and if it implements FullDataTimeline, it must not increase from calls to insert_operation either.

They also *should* obey these conditions:
* whenever the structure stores obsolete information to maintain a snapshot, it should notify the snapshot using snapshot.????? so that the snapshot may free up the memory using forget_snapshot() when it is dropped.

*/
struct QueryResult <Timeline: DataTimeline> {
  data: Timeline::QueryResultData;
  valid_until: something < ExtendedTime <Whatever::Steward::Basics>>;
}
struct OperationResult <Timeline: DataTimeline> {
  invalidated_queries: Vec<InvalidationHandle>;
  deleted_future_operations: Vec<(EventHandle, Operation)>; ?????
  created_predictors: Vec<PredictorHandle>;
  deleted_predictors: Vec<PredictorHandle>;
}
struct CreationResult <Timeline: DataTimeline> {
  created_predictors: Vec<PredictorHandle>;
}
trait DataTimeline {

  type Steward: TimeSteward;

  // All inputs are required to have a standard format, so that the structure can be audited.
  type Query: StewardData;
  type QueryResultData: StewardData;
  type Operation: StewardData;
  type Snapshot: StewardData;

  fn with_steward (steward: StewardHandle <Self::Steward>)->Self;
  fn from_snapshot (steward: StewardHandle <Self::Steward>, snapshot: &Self::Snapshot)->Self;

  fn query <A: Accessor> (&self, query: Self::Query, accessor: &A)->Result <QueryResult<Self>,>;

  // note: I'm not sure this needs an error mode, because having a snapshot prior to the valid_since of a data timeline might be a caller error in a TimeSteward
  fn snapshot (snapshot: &Self::Steward::Snapshot)->Snapshot;

  /// requires a &Steward only so that you can't do it in a predictor or event function.
  //Maybe this should also return a range of times changed so you know what snapshots need to be taken?
  fn insert_operation (&mut self, time: ExtendedTime <Self::Steward::Basics>, operation: Self::Operation, & Steward)->Result <,>;

  fn valid_since (&self, & Steward)->ValidSince <ExtendedTime <Self::Steward::Basics>>;
  fn forget_before (&mut self, time: ExtendedTime <Self::Steward::Basics>, & Steward);
  fn forget_snapshot (&mut self, StewardRc <Steward::Snapshot>);

  // query functions, which take an accessor and possibly a prediction handle, which may be stored in self for future invalidation
  // modify functions, which take a mutator and
  // - possibly return invalidated prediction handles
  // – possibly return spawned predictions, as from creating a new entity
  // - assuming this is for a full TimeSteward, return a StewardRc <TimeStewardModificationReverter> (which, for the simple case, may be a Self). This makes each potential reversion take at least a fat-pointer to store, unless we can make StewardRc be a thin pointer with the vtable at the destination.

  //An operation at time T may create new predictors from T to other times, destroy predictors from T to other times, or invalidate predictions that include After (T).
}

#[derive (Clone)]
struct StewardHandle <Steward: TimeSteward> {

}
impl <Steward: TimeSteward> StewardHandle <Steward> {
  fn snapshots (&self)->& SnapshotTree <Steward>;
}
impl <Steward: TimeSteward> SnapshotTree <Steward> {
  fn iterate_snapshots (time_range, since_snapshot_number)->impl Iter<Item = (&Steward::Basics::Time, &StewardRc <Steward::Snapshot>)>;
}

trait EntityHistory {
  type Steward: Steward;
  fn get (m: & Steward::Mutator) {
}
struct TypedEntityHistory<E:Entity, S: Steward> {
  data: Steward::EntityHistory;
}
impl TypedEntityHistory {
  fn get (m: & S::Mutator) {self.data.get (m).downcast_ref().expect()}
}

trait Entity {
  type Varying = Self;
  type Constants = ();
}

trait Mutator : ??? + Rng {
  type Steward: Steward;
  fn create <E: Entity> (&mut self, constants: E::Constants)->TypedEntityHistory <E, B::S>;
  fn get <E: Entity> (&self, t: TypedEntityHistory <E, B::S>)->E::Varying {t.data.get (...).downcast_ref().expect()}
  ;
}

trait Steward {
  type Mutator: Mutator <Steward = Self>;
  type EntityHistory: EntityHistory <Steward = Self>;
}

impl Event for Struct {
  ...
  fn call <M: Mutator <...>> (& self, mutator: M) {
    let history: TypedEntityHistory <MyType, M::Steward> = self.entity_history;
    let value: &MyType = history.get (mutator);

    let new_history = mutator.create <MyType>(constants);
  }
}

<|endoftext|>


<commit_before>#![macro_escape]
use vm::{VM, Value, Int, Float, Function, Userdata, StackFrame, Data};
use typecheck::{TcType, Typed, FunctionType, unit_type_tc, bool_type_tc, int_type_tc, float_type_tc};
use compiler::CallGlobal;
use std::any::{Any, AnyRefExt};
use std::boxed::BoxAny;

pub trait VMType {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType;
    fn make_type(&self, vm: &VM) -> TcType {
        self.vm_type(vm).clone()
    }
}
pub trait VMValue : VMType {
    fn push(self, stack: &mut StackFrame);
    fn from_value(value: Value) -> Option<Self>;
}
impl VMType for () {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &unit_type_tc
    }
}
impl VMValue for () {
    fn push(self, _: &mut StackFrame) {
    }
    fn from_value(_: Value) -> Option<()> {
        Some(())
    }
}

impl VMType for int {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &int_type_tc
    }
}
impl VMValue for int {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(self));
    }
    fn from_value(value: Value) -> Option<int> {
        match value {
            Int(i) => Some(i),
            _ => None
        }
    }
}
impl VMType for f64 {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &float_type_tc
    }
}
impl VMValue for f64 {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Float(self));
    }
    fn from_value(value: Value) -> Option<f64> {
        match value {
            Float(f) => Some(f),
            _ => None
        }
    }
}
impl VMType for bool {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &bool_type_tc
    }
}
impl VMValue for bool {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(if self { 1 } else { 0 }));
    }
    fn from_value(value: Value) -> Option<bool> {
        match value {
            Int(1) => Some(true),
            Int(0) => Some(false),
            _ => None
        }
    }
}
impl <T: 'static + BoxAny + Clone> VMType for Box<T> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
}
impl <T: 'static + BoxAny + Clone> VMValue for Box<T> {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<Box<T>> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<T>().map(|x| box x.clone()),
            _ => None
        }
    }
}
impl <T: 'static> VMType for *mut T {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
}
impl <T: 'static> VMValue for *mut T {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(box self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<*mut T> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<*mut T>().map(|x| *x),
            _ => None
        }
    }
}

fn vm_type<'a, T: VMValue>(vm: &'a VM) -> &'a TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.vm_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

fn make_type<'a, T: VMValue>(vm: &'a VM) -> TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.make_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

trait Get<'a> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Self>;
}
macro_rules! make_get(
    ($($args:ident),* -> $result:ident) => (
impl <'a, $($args : VMValue),*, $result: VMValue> Get<'a> for Callable<'a, ($($args),*), $result> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, ($($args),*), $result>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        let mut arg_iter = args.iter();
                        let ok = $({
                            arg_iter.next().unwrap() == vm_type::<$args>(vm)
                            })&&*;
                        if arg_iter.next().is_none() && ok && **return_type == *vm_type::<$result>(vm) {
                            Some(FunctionRef { value: function_ref })
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}
))

make_get!(A, B -> R)

impl <'a, T: VMValue, R: VMValue> Get<'a> for Callable<'a, (T,), R> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, (T,), R>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        if args.len() == 1 {
                            let ok = args[0] == *vm_type::<T>(vm);
                            if ok && **return_type == *vm_type::<R>(vm) {
                                Some(FunctionRef { value: function_ref })
                            }
                            else {
                                None
                            }
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}

pub struct Callable<'a, Args, R> {
    vm: &'a mut VM,
    value: FunctionRef<Args, R>
}
struct FunctionRef<Args, R> {
    value: uint
}

impl <Args, R> VMType for FunctionRef<Args, R> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<|Args|:'static -> R>()
    }
}

impl <Args, R> VMValue for FunctionRef<Args, R> {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Function(self.value));
    }
    fn from_value(value: Value) -> Option<FunctionRef<Args, R>> {
        match value {
            Function(i) => Some(FunctionRef { value: i }),//TODO not type safe
            _ => None
        }
    }
}

impl <'a, A: VMValue, R: VMValue> Callable<'a, (A,), R> {
    pub fn call(&mut self, a: A) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(1)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}
impl <'a, A: VMValue, B: VMValue, R: VMValue> Callable<'a, (A, B), R> {
    pub fn call2(&mut self, a: A, b: B) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            b.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(2)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}

pub fn get_function<'a, T: Get<'a>>(vm: &'a mut VM, name: &str) -> Option<T> {
    Get::get_function(vm, name)
}

trait VMFunction {
    fn unpack_and_call(mut stack: StackFrame, f: Self);
}

macro_rules! make_vm_function(
    ($($args:ident),*) => (
impl <$($args: VMValue,)* R: VMValue> VMType for fn ($($args),*) -> R {
    #[allow(non_snake_case)]
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<fn ($($args),*) -> R>()
    }
    #[allow(non_snake_case)]
    fn make_type(&self, vm: &VM) -> TcType {
        FunctionType(vec![$(make_type::<$args>(vm)),*], box make_type::<R>(vm))
    }
}

impl <$($args : VMValue,)* R: VMValue> VMFunction for fn ($($args),*) -> R {
    #[allow(non_snake_case)]
    fn unpack_and_call(mut stack: StackFrame, f: fn ($($args),*) -> R) {
        let mut i = 0u;
        $(let $args = {
            let x = VMValue::from_value(stack[i].clone()).unwrap();
            i += 1;
            x
        });*;
        drop(i);//Avoid unused warnings
        let r = f($($args),*);
        r.push(&mut stack);
    }
}
    )
)

make_vm_function!()
make_vm_function!(A)
make_vm_function!(A, B)
make_vm_function!(A, B, C)
make_vm_function!(A, B, C, D)
make_vm_function!(A, B, C, D, E)
make_vm_function!(A, B, C, D, E, F)
make_vm_function!(A, B, C, D, E, F, G)

#[macro_export]
macro_rules! vm_function(
    ($func: expr) => ({
        fn wrapper(_: &VM, stack: StackFrame) {
            VMFunction::unpack_and_call(stack, $func)
        }
        wrapper
    })
)

#[macro_export]
macro_rules! define_function(
    ($vm: expr, $name: expr, $func: expr) => ({
        let vm = $vm;
        let (args, ret) = match $func.make_type(vm) {
            FunctionType(ref args, ref return_type) => (args.clone(), (**return_type).clone()),
            _ => fail!()
        };
        vm.extern_function($name, args, ret, vm_function!($func))
    })
)

#[cfg(test)]
mod tests {
    use super::{Get, Callable, VMType, VMFunction};

    use typecheck::FunctionType;
    use vm::{VM, load_script, StackFrame};
    use std::io::BufReader;

    #[test]
    fn call_function() {
        let s =
r"
fn add10(x: int) -> int {
    x + 10
}
fn mul(x: float, y: float) -> float {
    x * y
}
";
        let mut vm = VM::new();
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));
        {
            let mut f: Callable<(int,), int> = Get::get_function(&mut vm, "add10")
                .expect("No function");
            let result = f.call(2);
            assert_eq!(result, 12);
        }
        let mut f: Callable<(f64, f64), f64> = Get::get_function(&mut vm, "mul")
            .expect("No function");
        let result = f.call2(4., 5.);
        assert_eq!(result, 20.);
    }
    #[test]
    fn pass_userdata() {
        let s =
r"
fn id(x: Test) -> Test {
    x
}
";
        let mut vm = VM::new();
        fn test(test: *mut Test) -> bool {
            let test = unsafe { &mut *test };
            let x = test.x == 123;
            test.x *= 2;
            x
        }
        struct Test {
            x: int
        }
        vm.register_type::<Test>("Test")
            .unwrap_or_else(|_| fail!("Could not add type"));
        define_function!(&mut vm, "test", test);
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));

        let mut test = Test { x: 123 };
        {
            let mut f: Callable<(*mut Test,), *mut Test> = Get::get_function(&mut vm, "id")
                .expect("No function id");
            let result = f.call(&mut test);
            assert!(result == &mut test as *mut Test);
        }
        let mut f: Callable<(*mut Test,), bool> = Get::get_function(&mut vm, "test")
            .expect("No function test");
        let result = f.call(&mut test);
        assert!(result);
        assert_eq!(test.x, 123 * 2);
    }
}
<commit_msg>Fix VMFunction not being exported<commit_after>#![macro_escape]
use vm::{VM, Value, Int, Float, Function, Userdata, StackFrame, Data};
use typecheck::{TcType, Typed, FunctionType, unit_type_tc, bool_type_tc, int_type_tc, float_type_tc};
use compiler::CallGlobal;
use std::any::{Any, AnyRefExt};
use std::boxed::BoxAny;

pub trait VMType {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType;
    fn make_type(&self, vm: &VM) -> TcType {
        self.vm_type(vm).clone()
    }
}
pub trait VMValue : VMType {
    fn push(self, stack: &mut StackFrame);
    fn from_value(value: Value) -> Option<Self>;
}
impl VMType for () {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &unit_type_tc
    }
}
impl VMValue for () {
    fn push(self, _: &mut StackFrame) {
    }
    fn from_value(_: Value) -> Option<()> {
        Some(())
    }
}

impl VMType for int {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &int_type_tc
    }
}
impl VMValue for int {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(self));
    }
    fn from_value(value: Value) -> Option<int> {
        match value {
            Int(i) => Some(i),
            _ => None
        }
    }
}
impl VMType for f64 {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &float_type_tc
    }
}
impl VMValue for f64 {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Float(self));
    }
    fn from_value(value: Value) -> Option<f64> {
        match value {
            Float(f) => Some(f),
            _ => None
        }
    }
}
impl VMType for bool {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &bool_type_tc
    }
}
impl VMValue for bool {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(if self { 1 } else { 0 }));
    }
    fn from_value(value: Value) -> Option<bool> {
        match value {
            Int(1) => Some(true),
            Int(0) => Some(false),
            _ => None
        }
    }
}
impl <T: 'static + BoxAny + Clone> VMType for Box<T> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
}
impl <T: 'static + BoxAny + Clone> VMValue for Box<T> {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<Box<T>> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<T>().map(|x| box x.clone()),
            _ => None
        }
    }
}
impl <T: 'static> VMType for *mut T {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
}
impl <T: 'static> VMValue for *mut T {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(box self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<*mut T> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<*mut T>().map(|x| *x),
            _ => None
        }
    }
}

fn vm_type<'a, T: VMValue>(vm: &'a VM) -> &'a TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.vm_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

fn make_type<'a, T: VMValue>(vm: &'a VM) -> TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.make_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

trait Get<'a> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Self>;
}
macro_rules! make_get(
    ($($args:ident),* -> $result:ident) => (
impl <'a, $($args : VMValue),*, $result: VMValue> Get<'a> for Callable<'a, ($($args),*), $result> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, ($($args),*), $result>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        let mut arg_iter = args.iter();
                        let ok = $({
                            arg_iter.next().unwrap() == vm_type::<$args>(vm)
                            })&&*;
                        if arg_iter.next().is_none() && ok && **return_type == *vm_type::<$result>(vm) {
                            Some(FunctionRef { value: function_ref })
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}
))

make_get!(A, B -> R)

impl <'a, T: VMValue, R: VMValue> Get<'a> for Callable<'a, (T,), R> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, (T,), R>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        if args.len() == 1 {
                            let ok = args[0] == *vm_type::<T>(vm);
                            if ok && **return_type == *vm_type::<R>(vm) {
                                Some(FunctionRef { value: function_ref })
                            }
                            else {
                                None
                            }
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}

pub struct Callable<'a, Args, R> {
    vm: &'a mut VM,
    value: FunctionRef<Args, R>
}
struct FunctionRef<Args, R> {
    value: uint
}

impl <Args, R> VMType for FunctionRef<Args, R> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<|Args|:'static -> R>()
    }
}

impl <Args, R> VMValue for FunctionRef<Args, R> {
    fn push(self, stack: &mut StackFrame) {
        stack.push(Function(self.value));
    }
    fn from_value(value: Value) -> Option<FunctionRef<Args, R>> {
        match value {
            Function(i) => Some(FunctionRef { value: i }),//TODO not type safe
            _ => None
        }
    }
}

impl <'a, A: VMValue, R: VMValue> Callable<'a, (A,), R> {
    pub fn call(&mut self, a: A) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(1)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}
impl <'a, A: VMValue, B: VMValue, R: VMValue> Callable<'a, (A, B), R> {
    pub fn call2(&mut self, a: A, b: B) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            b.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(2)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}

pub fn get_function<'a, T: Get<'a>>(vm: &'a mut VM, name: &str) -> Option<T> {
    Get::get_function(vm, name)
}

trait VMFunction {
    fn unpack_and_call(mut stack: StackFrame, f: Self);
}

macro_rules! make_vm_function(
    ($($args:ident),*) => (
impl <$($args: VMValue,)* R: VMValue> VMType for fn ($($args),*) -> R {
    #[allow(non_snake_case)]
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<fn ($($args),*) -> R>()
    }
    #[allow(non_snake_case)]
    fn make_type(&self, vm: &VM) -> TcType {
        FunctionType(vec![$(make_type::<$args>(vm)),*], box make_type::<R>(vm))
    }
}

impl <$($args : VMValue,)* R: VMValue> VMFunction for fn ($($args),*) -> R {
    #[allow(non_snake_case)]
    fn unpack_and_call(mut stack: StackFrame, f: fn ($($args),*) -> R) {
        let mut i = 0u;
        $(let $args = {
            let x = VMValue::from_value(stack[i].clone()).unwrap();
            i += 1;
            x
        });*;
        drop(i);//Avoid unused warnings
        let r = f($($args),*);
        r.push(&mut stack);
    }
}
    )
)
fn unpack_and_call<F: VMFunction>(stack: StackFrame, f: F) {
    VMFunction::unpack_and_call(stack, f)
}

make_vm_function!()
make_vm_function!(A)
make_vm_function!(A, B)
make_vm_function!(A, B, C)
make_vm_function!(A, B, C, D)
make_vm_function!(A, B, C, D, E)
make_vm_function!(A, B, C, D, E, F)
make_vm_function!(A, B, C, D, E, F, G)

#[macro_export]
macro_rules! vm_function(
    ($func: expr) => ({
        fn wrapper(_: &VM, stack: StackFrame) {
            unpack_and_call(stack, $func)
        }
        wrapper
    })
)

#[macro_export]
macro_rules! define_function(
    ($vm: expr, $name: expr, $func: expr) => ({
        let vm = $vm;
        let (args, ret) = match $func.make_type(vm) {
            FunctionType(ref args, ref return_type) => (args.clone(), (**return_type).clone()),
            _ => fail!()
        };
        vm.extern_function($name, args, ret, vm_function!($func))
    })
)

#[cfg(test)]
mod tests {
    use super::{Get, Callable, VMType, VMFunction};

    use typecheck::FunctionType;
    use vm::{VM, load_script, StackFrame};
    use std::io::BufReader;

    #[test]
    fn call_function() {
        let s =
r"
fn add10(x: int) -> int {
    x + 10
}
fn mul(x: float, y: float) -> float {
    x * y
}
";
        let mut vm = VM::new();
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));
        {
            let mut f: Callable<(int,), int> = Get::get_function(&mut vm, "add10")
                .expect("No function");
            let result = f.call(2);
            assert_eq!(result, 12);
        }
        let mut f: Callable<(f64, f64), f64> = Get::get_function(&mut vm, "mul")
            .expect("No function");
        let result = f.call2(4., 5.);
        assert_eq!(result, 20.);
    }
    #[test]
    fn pass_userdata() {
        let s =
r"
fn id(x: Test) -> Test {
    x
}
";
        let mut vm = VM::new();
        fn test(test: *mut Test) -> bool {
            let test = unsafe { &mut *test };
            let x = test.x == 123;
            test.x *= 2;
            x
        }
        struct Test {
            x: int
        }
        vm.register_type::<Test>("Test")
            .unwrap_or_else(|_| fail!("Could not add type"));
        define_function!(&mut vm, "test", test);
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));

        let mut test = Test { x: 123 };
        {
            let mut f: Callable<(*mut Test,), *mut Test> = Get::get_function(&mut vm, "id")
                .expect("No function id");
            let result = f.call(&mut test);
            assert!(result == &mut test as *mut Test);
        }
        let mut f: Callable<(*mut Test,), bool> = Get::get_function(&mut vm, "test")
            .expect("No function test");
        let result = f.call(&mut test);
        assert!(result);
        assert_eq!(test.x, 123 * 2);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{DetachDataDisposition, Heap, JSContext, JSObject, JS_DetachArrayBuffer};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> AudioBuffer {
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            match initial_data {
                Some(data) => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&data[offset..offset + (length as usize) - 1]),
                            array.handle_mut(),
                        )
                    };
                },
                None => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&vec![0.; length as usize]),
                            array.handle_mut(),
                        )
                    };
                }
            }
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(
            global,
            number_of_channels,
            length,
            sample_rate,
            initial_data,
        );
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let _ = JS_DetachArrayBuffer(cx, channel.handle(), DetachDataDisposition::KeepData);
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe {
                array.update(&source.as_slice()[offset..offset + bytes_to_copy]);
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Root JS channels during AudioBuffer construction<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{DetachDataDisposition, Heap, JSContext, JSObject, JS_DetachArrayBuffer};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};
use std::mem;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> AudioBuffer {
        let cx = global.get_cx();
        rooted_vec!(let mut js_channels_);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            match initial_data {
                Some(data) => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&data[offset..offset + (length as usize) - 1]),
                            array.handle_mut(),
                        )
                    };
                },
                None => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&vec![0.; length as usize]),
                            array.handle_mut(),
                        )
                    };
                }
            }
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels_.push(js_channel);
        }
        let js_channels = DomRefCell::new(Vec::new());
        mem::swap(&mut *js_channels.borrow_mut(), &mut *js_channels_);
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels,
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(
            global,
            number_of_channels,
            length,
            sample_rate,
            initial_data,
        );
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let _ = JS_DetachArrayBuffer(cx, channel.handle(), DetachDataDisposition::KeepData);
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe {
                array.update(&source.as_slice()[offset..offset + bytes_to_copy]);
            }
        } else {
            return Err(Error::IndexSize);
        }

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


<commit_before>use std::hash;
use std::hash::Hash;

#[derive(Show)]
pub enum Exp<'x> {
    Value(int),
    Plus(Box<Exp<'x>>, Box<Exp<'x>>),
    Ref(&'x Exp<'x>)
}

#[test]
pub fn print() {
    let e = Exp::Plus(box Exp::Value(1),
                      box Exp::Plus(box Exp::Value(2),
                                    box Exp::Plus(box Exp::Value(3),
                                                  box Exp::Plus(box Exp::Value(4),
                                                                box Exp::Value(5))))) ;
    print!("{}", e);
}

pub fn main () {
    let e = Exp::Plus(box Exp::Value(1),
                      box Exp::Plus(box Exp::Value(2),
                                    box Exp::Plus(box Exp::Value(3),
                                                  box Exp::Plus(box Exp::Value(4),
                                                                box Exp::Value(5))))) ;
    print!("{}", e);
}
<commit_msg>wrote small-step interpreter that uses sharing<commit_after>use std::hash;
use std::hash::Hash;

#[derive(Show,Clone)]
pub enum Exp<'x> {
    Value(int),
    Plus(Box<Exp<'x>>, Box<Exp<'x>>),
    Ref(&'x Exp<'x>) // Refs allow for (non-affine) sharing.
}

pub fn step<'x> (e:&'x Exp<'x>) -> Option<Exp<'x>> {
    match *e {
        Exp::Value(_) => None,
        Exp::Ref(e) => step(e),
        Exp::Plus(ref e1, ref e2) =>
            match **e1 {
                Exp::Value(n) =>
                    match **e2 {
                        Exp::Value(m) => Some(Exp::Value(n+m)),
                        _ => {
                            let e2_ = step(&**e2) ;
                            match e2_ {
                                None => panic!("impossible"),
                                Some(e2_) => Some(Exp::Plus(box Exp::Value(n), box e2_))
                            }
                        }
                    },

                _ => {
                    let e1_ = step(&**e1) ;
                    match e1_ {
                        None => panic!("impossible"),
                        Some(e1_) => Some(Exp::Plus(box e1_, box Exp::Ref(&**e2)))
                    }
                }
            }
    }
}

#[test]
pub fn print() {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(e0) ;
    let e2 = step(e1) ;
    let e3 = step(e2) ;
    print!("{} {} {} {}", e0, e1, e2, e3);
}

pub fn test1 () {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(&e0) ;
    match e1 {
        None => (),
        Some(ref e1) => {
            println!("{} --> {}", e0, e1) ;
            let e2 = step( e1 ) ;
            match e2 {
                None => (),
                Some(ref e2) => {
                    println!("{} --> {}", e1, e2) ;
                    let e3 = step( e2 ) ;
                    match e3 {
                        None => (),
                        Some(ref e3) => {
                            println!("{} --> {}", e2, e3) ;
                            let e4 = step( e3 ) ;
                            match e4 {
                                None => (),
                                Some(ref e4) => {
                                    println!("{} --> {}", e3, e4) ;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

pub fn test2 () {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let mut exp = & e0 ;
    loop {
        let s = step(&e0) ;
        match s {
            None => break,
            Some(ref exp_) => {
                println!("{} --> {}", exp, exp_) ;
                // exp = exp_.clone () ;
                continue
            }
        }
    }
}

pub fn main () {
    if true {
        test1 ()
    }
    else {
        test2 ()
    }
}

//     let mut e = e0.clone () ;
// loop {
//         match step(&e) {
//             None => break,
//             Some(e2) => {
//                 println!("{} --> {}", e, e2) ;
//                 //let e3 = e2.clone() ;
//                 //e = e3 ;
//                 continue ;
//             }
//     }}
// }
<|endoftext|>