<commit_before>use super::Parser;

#[test]
fn test_parse_number() {
    let mut parser = Parser::new("1".chars());
    assert_eq!(e_number![1.],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_string() {
    let s = "rust we're looking forward on beta";
    let input = format!(r#""{}""#, s);
    let mut parser = Parser::new(input.chars());
    assert_eq!(e_string![s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_symbol() {
    let s = "symbol";
    let mut parser = Parser::new(s.chars());
    assert_eq!(e_symbol![s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_ns_qualified_symbol() {
    let ns = "my-ns";
    let s = "symbol";
    let ns_qualified_symbol = format!("{}/{}", ns, s);
    let mut parser = Parser::new(ns_qualified_symbol.chars());
    assert_eq!(e_symbol![ns, s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_keyword() {
    let mut parser = Parser::new(":keyword".chars());
    assert_eq!(e_keyword!["keyword"],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_ns_qualified_keyword() {
    let mut parser = Parser::new(":my-ns/keyword".chars());
    assert_eq!(e_keyword!["my-ns", "keyword"],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_list_expression() {
    let expected_result = e_list![e_symbol!("def"),
                                  e_symbol!("a"),
                                  e_number!(1_f64)];
    let mut parser = Parser::new("(def a 1)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_vec_expression() {
    let expected_result = e_vec![e_keyword!("1"),
                                 e_keyword!("2"),
                                 e_keyword!("3")];
    let mut parser = Parser::new("[:1 :2 :3]".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_nested_list_expressions() {
    let expected_result =  e_list![e_symbol!("def"),
                                   e_symbol!("a"),
                                   e_list![e_symbol!("+"),
                                           e_number!(1_f64),
                                           e_number!(2_f64)]];
    let mut parser = Parser::new("(def a (+ 1 2))".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_nested_vec_expressions() {
    let expected_result =  e_vec![e_number!(1.),
                                  e_number!(2.),
                                  e_list![e_symbol!("+"),
                                          e_number!(1_f64),
                                          e_number!(2_f64)],
                                  e_keyword!["k"]];
    let mut parser = Parser::new("[1 2 (+ 1 2) :k]".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_quoted_list() {
    let expected_result =  e_list![e_symbol!["quote"],
                                   e_list![e_symbol!["+"],
                                           e_number![1.],
                                           e_number![2.]]];
    let mut parser = Parser::new("'(+ 1 2)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_unquoted_symbol() {
    let expected_result =  e_list![e_symbol!["unquote"],
                                   e_symbol!["symbol"]];
    let mut parser = Parser::new("~symbol".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_unquoted_splicing_list() {
    let expected_result =  e_list![e_symbol!["unquote-splicing"],
                                   e_list![e_number![1.],
                                           e_number![2.],
                                           e_number![3.]]];
    let mut parser = Parser::new("~@(1 2 3)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}
<commit_msg>Add test for parsing syntax quoted list<commit_after>use super::Parser;

#[test]
fn test_parse_number() {
    let mut parser = Parser::new("1".chars());
    assert_eq!(e_number![1.],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_string() {
    let s = "rust we're looking forward on beta";
    let input = format!(r#""{}""#, s);
    let mut parser = Parser::new(input.chars());
    assert_eq!(e_string![s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_symbol() {
    let s = "symbol";
    let mut parser = Parser::new(s.chars());
    assert_eq!(e_symbol![s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_ns_qualified_symbol() {
    let ns = "my-ns";
    let s = "symbol";
    let ns_qualified_symbol = format!("{}/{}", ns, s);
    let mut parser = Parser::new(ns_qualified_symbol.chars());
    assert_eq!(e_symbol![ns, s],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_keyword() {
    let mut parser = Parser::new(":keyword".chars());
    assert_eq!(e_keyword!["keyword"],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_ns_qualified_keyword() {
    let mut parser = Parser::new(":my-ns/keyword".chars());
    assert_eq!(e_keyword!["my-ns", "keyword"],
               parser.next().unwrap().ok().unwrap())
}

#[test]
fn test_parse_list_expression() {
    let expected_result = e_list![e_symbol!("def"),
                                  e_symbol!("a"),
                                  e_number!(1_f64)];
    let mut parser = Parser::new("(def a 1)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_vec_expression() {
    let expected_result = e_vec![e_keyword!("1"),
                                 e_keyword!("2"),
                                 e_keyword!("3")];
    let mut parser = Parser::new("[:1 :2 :3]".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_nested_list_expressions() {
    let expected_result =  e_list![e_symbol!("def"),
                                   e_symbol!("a"),
                                   e_list![e_symbol!("+"),
                                           e_number!(1_f64),
                                           e_number!(2_f64)]];
    let mut parser = Parser::new("(def a (+ 1 2))".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_nested_vec_expressions() {
    let expected_result =  e_vec![e_number!(1.),
                                  e_number!(2.),
                                  e_list![e_symbol!("+"),
                                          e_number!(1_f64),
                                          e_number!(2_f64)],
                                  e_keyword!["k"]];
    let mut parser = Parser::new("[1 2 (+ 1 2) :k]".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_quoted_list() {
    let expected_result =  e_list![e_symbol!["quote"],
                                   e_list![e_symbol!["+"],
                                           e_number![1.],
                                           e_number![2.]]];
    let mut parser = Parser::new("'(+ 1 2)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_unquoted_symbol() {
    let expected_result =  e_list![e_symbol!["unquote"],
                                   e_symbol!["symbol"]];
    let mut parser = Parser::new("~symbol".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_unquoted_splicing_list() {
    let expected_result =  e_list![e_symbol!["unquote-splicing"],
                                   e_list![e_number![1.],
                                           e_number![2.],
                                           e_number![3.]]];
    let mut parser = Parser::new("~@(1 2 3)".chars());
    let actual_result = parser.next().unwrap().ok().unwrap();
    assert_eq!(expected_result, actual_result);
}

#[test]
fn test_parse_syntax_quoted_list() {
    let expected_result = e_list![e_symbol!["syntax-quote"],
                                  e_list![e_symbol!["+"],
                                          e_number![1.],
                                          e_number![2.]]];
    let mut parser = Parser::new("`(+ 1 2)".chars());
    assert_eq!(expected_result, parser.next().unwrap().ok().unwrap());
}
<|endoftext|>


<commit_before>// compile-flags: -Zmiri-seed=0000000000000000

fn main() {
    let x = &42 as *const i32 as usize;
    let y = x * 2;
    assert_eq!(y, x + x);
    let z = y as u8 as usize;
    assert_eq!(z, y % 256);
}
<commit_msg>Auto merge of #798 - RalfJung:format-ptr, r=RalfJung<commit_after>// compile-flags: -Zmiri-seed=0000000000000000

fn main() {
    // Some casting-to-int with arithmetic.
    let x = &42 as *const i32 as usize;
    let y = x * 2;
    assert_eq!(y, x + x);
    let z = y as u8 as usize;
    assert_eq!(z, y % 256);

    // Pointer string formatting! We can't check the output as it changes when libstd changes,
    // but we can make sure Miri does not error.
    format!("{:?}", &mut 13 as *mut _);
}
<|endoftext|>


<commit_before>#![feature(async_closure)]
#![feature(box_patterns)]
#![feature(generic_associated_types)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(try_trait_v2)]
#![allow(clippy::module_inception)]

mod builtin_functions;
mod compiler;
mod database;
mod fuzzer;
mod language_server;
mod module;
mod vm;

use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst_to_ast::CstToAst,
        error::CompilerError,
        hir::{self, CollectErrors, Id},
        hir_to_lir::HirToLir,
        rcst_to_cst::RcstToCst,
        string_to_rcst::StringToRcst,
    },
    database::Database,
    language_server::utils::LspPositionConversion,
    module::{Module, ModuleKind},
    vm::{
        context::{DbUseProvider, RunForever},
        tracer::{FullTracer, Tracer},
        Closure, ExecutionResult, FiberId, Status, Struct, Vm,
    },
};
use compiler::lir::Lir;
use itertools::Itertools;
use language_server::CandyLanguageServer;
use notify::{watcher, RecursiveMode, Watcher};
use std::{
    collections::HashMap,
    convert::TryInto,
    env::current_dir,
    path::PathBuf,
    sync::{mpsc::channel, Arc},
    time::Duration,
};
use structopt::StructOpt;
use tower_lsp::{LspService, Server};
use tracing::{debug, error, info, warn, Level, Metadata};
use tracing_subscriber::{filter, fmt::format::FmtSpan, prelude::*};
use vm::{ChannelId, CompletedOperation, OperationId};

#[derive(StructOpt, Debug)]
#[structopt(name = "candy", about = "The 🍭 Candy CLI.")]
enum CandyOptions {
    Build(CandyBuildOptions),
    Run(CandyRunOptions),
    Fuzz(CandyFuzzOptions),
    Lsp,
}

#[derive(StructOpt, Debug)]
struct CandyBuildOptions {
    #[structopt(long)]
    debug: bool,

    #[structopt(long)]
    watch: bool,

    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[derive(StructOpt, Debug)]
struct CandyRunOptions {
    #[structopt(long)]
    debug: bool,

    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[derive(StructOpt, Debug)]
struct CandyFuzzOptions {
    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[tokio::main]
async fn main() {
    init_logger();
    match CandyOptions::from_args() {
        CandyOptions::Build(options) => build(options),
        CandyOptions::Run(options) => run(options),
        CandyOptions::Fuzz(options) => fuzz(options).await,
        CandyOptions::Lsp => lsp().await,
    }
}

fn build(options: CandyBuildOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );
    raw_build(module.clone(), options.debug);

    if options.watch {
        let (tx, rx) = channel();
        let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
        watcher
            .watch(&options.file, RecursiveMode::Recursive)
            .unwrap();
        loop {
            match rx.recv() {
                Ok(_) => {
                    raw_build(module.clone(), options.debug);
                }
                Err(e) => error!("watch error: {e:#?}"),
            }
        }
    }
}
fn raw_build(module: Module, debug: bool) -> Option<Arc<Lir>> {
    let db = Database::default();

    tracing::span!(Level::DEBUG, "Parsing string to RCST").in_scope(|| {
        let rcst = db
            .rcst(module.clone())
            .unwrap_or_else(|err| panic!("Error parsing file `{}`: {:?}", module, err));
        if debug {
            module.dump_associated_debug_file("rcst", &format!("{:#?}\n", rcst));
        }
    });

    tracing::span!(Level::DEBUG, "Turning RCST to CST").in_scope(|| {
        let cst = db.cst(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("cst", &format!("{:#?}\n", cst));
        }
    });

    tracing::span!(Level::DEBUG, "Abstracting CST to AST").in_scope(|| {
        let (asts, ast_cst_id_map) = db.ast(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file(
                "ast",
                &format!("{}\n", asts.iter().map(|ast| format!("{}", ast)).join("\n")),
            );
            module.dump_associated_debug_file(
                "ast_to_cst_ids",
                &ast_cst_id_map
                    .keys()
                    .into_iter()
                    .sorted_by_key(|it| it.local)
                    .map(|key| format!("{key} -> {}\n", ast_cst_id_map[key].0))
                    .join(""),
            );
        }
    });

    tracing::span!(Level::DEBUG, "Turning AST to HIR").in_scope(|| {
        let (hir, hir_ast_id_map) = db.hir(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("hir", &format!("{}", hir));
            module.dump_associated_debug_file(
                "hir_to_ast_ids",
                &hir_ast_id_map
                    .keys()
                    .into_iter()
                    .map(|key| format!("{key} -> {}\n", hir_ast_id_map[key]))
                    .join(""),
            );
        }
        let mut errors = vec![];
        hir.collect_errors(&mut errors);
        for CompilerError { span, payload, .. } in errors {
            let (start_line, start_col) = db.offset_to_lsp(module.clone(), span.start);
            let (end_line, end_col) = db.offset_to_lsp(module.clone(), span.end);
            warn!("{start_line}:{start_col} – {end_line}:{end_col}: {payload:?}");
        }
    });

    let lir = tracing::span!(Level::DEBUG, "Lowering HIR to LIR").in_scope(|| {
        let lir = db.lir(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("lir", &format!("{lir}"));
        }
        lir
    });

    Some(lir)
}

fn run(options: CandyRunOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );
    let db = Database::default();

    if raw_build(module.clone(), false).is_none() {
        warn!("Build failed.");
        return;
    };
    // TODO: Optimize the code before running.

    let path_string = options.file.to_string_lossy();
    debug!("Running `{path_string}`.");

    let module_closure = Closure::of_module(&db, module.clone()).unwrap();
    let mut tracer = FullTracer::new();

    let mut vm = Vm::new();
    vm.set_up_for_running_module_closure(module_closure);
    vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer);
    if let Status::WaitingForOperations = vm.status() {
        error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it.");
        // TODO: Show stack traces of all fibers?
    }
    let result = vm.tear_down();

    if options.debug {
        module.dump_associated_debug_file("trace", &format!("{tracer:?}"));
    }

    let (mut heap, exported_definitions): (_, Struct) = match result {
        ExecutionResult::Finished(return_value) => {
            debug!("The module exports these definitions: {return_value:?}",);
            let exported = return_value
                .heap
                .get(return_value.address)
                .data
                .clone()
                .try_into()
                .unwrap();
            (return_value.heap, exported)
        }
        ExecutionResult::Panicked {
            reason,
            responsible,
        } => {
            error!("The module panicked because {reason}.");
            if let Some(responsible) = responsible {
                error!("{responsible} is responsible.");
            } else {
                error!("Some top-level code panics.");
            }
            error!(
                "This is the stack trace:\n{}",
                tracer.format_panic_stack_trace_to_root_fiber(&db)
            );
            return;
        }
    };

    let main = heap.create_symbol("Main".to_string());
    let main = match exported_definitions.get(&heap, main) {
        Some(main) => main,
        None => {
            error!("The module doesn't contain a main function.");
            return;
        }
    };

    debug!("Running main function.");
    // TODO: Add more environment stuff.
    let mut vm = Vm::new();
    let mut stdout = StdoutService::new(&mut vm);
    let environment = {
        let stdout_symbol = heap.create_symbol("Stdout".to_string());
        let stdout_port = heap.create_send_port(stdout.channel);
        heap.create_struct(HashMap::from([(stdout_symbol, stdout_port)]))
    };
    tracer.in_fiber_tracer(FiberId::root()).call_started(
        &heap,
        Id::new(module, vec!["main".to_string()]),
        main,
        vec![environment],
    );
    vm.set_up_for_running_closure(heap, main, &[environment]);
    loop {
        match vm.status() {
            Status::CanRun => {
                debug!("VM still running.");
                vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer);
            }
            Status::WaitingForOperations => {
                todo!("VM can't proceed until some operations complete.");
            }
            _ => break,
        }
        stdout.run(&mut vm);
        for channel in vm.unreferenced_channels.iter().copied().collect_vec() {
            if channel != stdout.channel {
                vm.free_channel(channel);
            }
        }
    }
    match vm.tear_down() {
        ExecutionResult::Finished(return_value) => {
            tracer
                .in_fiber_tracer(FiberId::root())
                .call_ended(&return_value.heap, return_value.address);
            debug!("The main function returned: {return_value:?}");
        }
        ExecutionResult::Panicked {
            reason,
            responsible,
        } => {
            error!("The main function panicked because {reason}.");
            if let Some(responsible) = responsible {
                error!("{responsible} is responsible.");
            } else {
                error!("A needs directly in the main function panicks. Perhaps the main functions expects more in the environment.");
            }
            error!(
                "This is the stack trace:\n{}",
                tracer.format_panic_stack_trace_to_root_fiber(&db)
            );
        }
    }
}

/// A state machine that corresponds to a loop that always calls `receive` on
/// the stdout channel and then logs that packet.
struct StdoutService {
    channel: ChannelId,
    current_receive: OperationId,
}
impl StdoutService {
    fn new(vm: &mut Vm) -> Self {
        let channel = vm.create_channel(1);
        let current_receive = vm.receive(channel);
        Self {
            channel,
            current_receive,
        }
    }
    fn run(&mut self, vm: &mut Vm) {
        if let Some(CompletedOperation::Received { packet }) =
            vm.completed_operations.remove(&self.current_receive)
        {
            info!("Sent to stdout: {packet:?}");
            self.current_receive = vm.receive(self.channel);
        }
    }
}

async fn fuzz(options: CandyFuzzOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );

    if raw_build(module.clone(), false).is_none() {
        warn!("Build failed.");
        return;
    }

    debug!("Fuzzing `{module}`.");
    let db = Database::default();
    fuzzer::fuzz(&db, module).await;
}

async fn lsp() {
    info!("Starting language server…");
    let (service, socket) = LspService::new(CandyLanguageServer::from_client);
    Server::new(tokio::io::stdin(), tokio::io::stdout(), socket)
        .serve(service)
        .await;
}

fn init_logger() {
    let console_log = tracing_subscriber::fmt::layer()
        .compact()
        .with_span_events(FmtSpan::ENTER)
        .with_filter(filter::filter_fn(|metadata| {
            // For external packages, show only the error logs.
            metadata.level() <= &Level::ERROR
                || metadata
                    .module_path()
                    .unwrap_or_default()
                    .starts_with("candy")
        }))
        .with_filter(filter::filter_fn(level_for("candy::compiler", Level::WARN)))
        .with_filter(filter::filter_fn(level_for(
            "candy::language_server",
            Level::DEBUG,
        )))
        .with_filter(filter::filter_fn(level_for("candy::vm", Level::DEBUG)))
        .with_filter(filter::filter_fn(level_for(
            "candy::vm::heap",
            Level::DEBUG,
        )));
    tracing_subscriber::registry().with(console_log).init();
}
fn level_for(module: &'static str, level: Level) -> impl Fn(&Metadata) -> bool {
    move |metadata| {
        if metadata
            .module_path()
            .unwrap_or_default()
            .starts_with(module)
        {
            metadata.level() <= &level
        } else {
            true
        }
    }
}
<commit_msg>Fix Clippy lints<commit_after>#![feature(async_closure)]
#![feature(box_patterns)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(try_trait_v2)]
#![allow(clippy::module_inception)]

mod builtin_functions;
mod compiler;
mod database;
mod fuzzer;
mod language_server;
mod module;
mod vm;

use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst_to_ast::CstToAst,
        error::CompilerError,
        hir::{self, CollectErrors, Id},
        hir_to_lir::HirToLir,
        rcst_to_cst::RcstToCst,
        string_to_rcst::StringToRcst,
    },
    database::Database,
    language_server::utils::LspPositionConversion,
    module::{Module, ModuleKind},
    vm::{
        context::{DbUseProvider, RunForever},
        tracer::{FullTracer, Tracer},
        Closure, ExecutionResult, FiberId, Status, Struct, Vm,
    },
};
use compiler::lir::Lir;
use itertools::Itertools;
use language_server::CandyLanguageServer;
use notify::{watcher, RecursiveMode, Watcher};
use std::{
    collections::HashMap,
    convert::TryInto,
    env::current_dir,
    path::PathBuf,
    sync::{mpsc::channel, Arc},
    time::Duration,
};
use structopt::StructOpt;
use tower_lsp::{LspService, Server};
use tracing::{debug, error, info, warn, Level, Metadata};
use tracing_subscriber::{filter, fmt::format::FmtSpan, prelude::*};
use vm::{ChannelId, CompletedOperation, OperationId};

#[derive(StructOpt, Debug)]
#[structopt(name = "candy", about = "The 🍭 Candy CLI.")]
enum CandyOptions {
    Build(CandyBuildOptions),
    Run(CandyRunOptions),
    Fuzz(CandyFuzzOptions),
    Lsp,
}

#[derive(StructOpt, Debug)]
struct CandyBuildOptions {
    #[structopt(long)]
    debug: bool,

    #[structopt(long)]
    watch: bool,

    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[derive(StructOpt, Debug)]
struct CandyRunOptions {
    #[structopt(long)]
    debug: bool,

    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[derive(StructOpt, Debug)]
struct CandyFuzzOptions {
    #[structopt(parse(from_os_str))]
    file: PathBuf,
}

#[tokio::main]
async fn main() {
    init_logger();
    match CandyOptions::from_args() {
        CandyOptions::Build(options) => build(options),
        CandyOptions::Run(options) => run(options),
        CandyOptions::Fuzz(options) => fuzz(options).await,
        CandyOptions::Lsp => lsp().await,
    }
}

fn build(options: CandyBuildOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );
    raw_build(module.clone(), options.debug);

    if options.watch {
        let (tx, rx) = channel();
        let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
        watcher
            .watch(&options.file, RecursiveMode::Recursive)
            .unwrap();
        loop {
            match rx.recv() {
                Ok(_) => {
                    raw_build(module.clone(), options.debug);
                }
                Err(e) => error!("watch error: {e:#?}"),
            }
        }
    }
}
fn raw_build(module: Module, debug: bool) -> Option<Arc<Lir>> {
    let db = Database::default();

    tracing::span!(Level::DEBUG, "Parsing string to RCST").in_scope(|| {
        let rcst = db
            .rcst(module.clone())
            .unwrap_or_else(|err| panic!("Error parsing file `{}`: {:?}", module, err));
        if debug {
            module.dump_associated_debug_file("rcst", &format!("{:#?}\n", rcst));
        }
    });

    tracing::span!(Level::DEBUG, "Turning RCST to CST").in_scope(|| {
        let cst = db.cst(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("cst", &format!("{:#?}\n", cst));
        }
    });

    tracing::span!(Level::DEBUG, "Abstracting CST to AST").in_scope(|| {
        let (asts, ast_cst_id_map) = db.ast(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file(
                "ast",
                &format!("{}\n", asts.iter().map(|ast| format!("{}", ast)).join("\n")),
            );
            module.dump_associated_debug_file(
                "ast_to_cst_ids",
                &ast_cst_id_map
                    .keys()
                    .into_iter()
                    .sorted_by_key(|it| it.local)
                    .map(|key| format!("{key} -> {}\n", ast_cst_id_map[key].0))
                    .join(""),
            );
        }
    });

    tracing::span!(Level::DEBUG, "Turning AST to HIR").in_scope(|| {
        let (hir, hir_ast_id_map) = db.hir(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("hir", &format!("{}", hir));
            module.dump_associated_debug_file(
                "hir_to_ast_ids",
                &hir_ast_id_map
                    .keys()
                    .into_iter()
                    .map(|key| format!("{key} -> {}\n", hir_ast_id_map[key]))
                    .join(""),
            );
        }
        let mut errors = vec![];
        hir.collect_errors(&mut errors);
        for CompilerError { span, payload, .. } in errors {
            let (start_line, start_col) = db.offset_to_lsp(module.clone(), span.start);
            let (end_line, end_col) = db.offset_to_lsp(module.clone(), span.end);
            warn!("{start_line}:{start_col} – {end_line}:{end_col}: {payload:?}");
        }
    });

    let lir = tracing::span!(Level::DEBUG, "Lowering HIR to LIR").in_scope(|| {
        let lir = db.lir(module.clone()).unwrap();
        if debug {
            module.dump_associated_debug_file("lir", &format!("{lir}"));
        }
        lir
    });

    Some(lir)
}

fn run(options: CandyRunOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );
    let db = Database::default();

    if raw_build(module.clone(), false).is_none() {
        warn!("Build failed.");
        return;
    };
    // TODO: Optimize the code before running.

    let path_string = options.file.to_string_lossy();
    debug!("Running `{path_string}`.");

    let module_closure = Closure::of_module(&db, module.clone()).unwrap();
    let mut tracer = FullTracer::new();

    let mut vm = Vm::new();
    vm.set_up_for_running_module_closure(module_closure);
    vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer);
    if let Status::WaitingForOperations = vm.status() {
        error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it.");
        // TODO: Show stack traces of all fibers?
    }
    let result = vm.tear_down();

    if options.debug {
        module.dump_associated_debug_file("trace", &format!("{tracer:?}"));
    }

    let (mut heap, exported_definitions): (_, Struct) = match result {
        ExecutionResult::Finished(return_value) => {
            debug!("The module exports these definitions: {return_value:?}",);
            let exported = return_value
                .heap
                .get(return_value.address)
                .data
                .clone()
                .try_into()
                .unwrap();
            (return_value.heap, exported)
        }
        ExecutionResult::Panicked {
            reason,
            responsible,
        } => {
            error!("The module panicked because {reason}.");
            if let Some(responsible) = responsible {
                error!("{responsible} is responsible.");
            } else {
                error!("Some top-level code panics.");
            }
            error!(
                "This is the stack trace:\n{}",
                tracer.format_panic_stack_trace_to_root_fiber(&db)
            );
            return;
        }
    };

    let main = heap.create_symbol("Main".to_string());
    let main = match exported_definitions.get(&heap, main) {
        Some(main) => main,
        None => {
            error!("The module doesn't contain a main function.");
            return;
        }
    };

    debug!("Running main function.");
    // TODO: Add more environment stuff.
    let mut vm = Vm::new();
    let mut stdout = StdoutService::new(&mut vm);
    let environment = {
        let stdout_symbol = heap.create_symbol("Stdout".to_string());
        let stdout_port = heap.create_send_port(stdout.channel);
        heap.create_struct(HashMap::from([(stdout_symbol, stdout_port)]))
    };
    tracer.in_fiber_tracer(FiberId::root()).call_started(
        &heap,
        Id::new(module, vec!["main".to_string()]),
        main,
        vec![environment],
    );
    vm.set_up_for_running_closure(heap, main, &[environment]);
    loop {
        match vm.status() {
            Status::CanRun => {
                debug!("VM still running.");
                vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer);
            }
            Status::WaitingForOperations => {
                todo!("VM can't proceed until some operations complete.");
            }
            _ => break,
        }
        stdout.run(&mut vm);
        for channel in vm.unreferenced_channels.iter().copied().collect_vec() {
            if channel != stdout.channel {
                vm.free_channel(channel);
            }
        }
    }
    match vm.tear_down() {
        ExecutionResult::Finished(return_value) => {
            tracer
                .in_fiber_tracer(FiberId::root())
                .call_ended(&return_value.heap, return_value.address);
            debug!("The main function returned: {return_value:?}");
        }
        ExecutionResult::Panicked {
            reason,
            responsible,
        } => {
            error!("The main function panicked because {reason}.");
            if let Some(responsible) = responsible {
                error!("{responsible} is responsible.");
            } else {
                error!("A needs directly in the main function panicks. Perhaps the main functions expects more in the environment.");
            }
            error!(
                "This is the stack trace:\n{}",
                tracer.format_panic_stack_trace_to_root_fiber(&db)
            );
        }
    }
}

/// A state machine that corresponds to a loop that always calls `receive` on
/// the stdout channel and then logs that packet.
struct StdoutService {
    channel: ChannelId,
    current_receive: OperationId,
}
impl StdoutService {
    fn new(vm: &mut Vm) -> Self {
        let channel = vm.create_channel(1);
        let current_receive = vm.receive(channel);
        Self {
            channel,
            current_receive,
        }
    }
    fn run(&mut self, vm: &mut Vm) {
        if let Some(CompletedOperation::Received { packet }) =
            vm.completed_operations.remove(&self.current_receive)
        {
            info!("Sent to stdout: {packet:?}");
            self.current_receive = vm.receive(self.channel);
        }
    }
}

async fn fuzz(options: CandyFuzzOptions) {
    let module = Module::from_package_root_and_file(
        current_dir().unwrap(),
        options.file.clone(),
        ModuleKind::Code,
    );

    if raw_build(module.clone(), false).is_none() {
        warn!("Build failed.");
        return;
    }

    debug!("Fuzzing `{module}`.");
    let db = Database::default();
    fuzzer::fuzz(&db, module).await;
}

async fn lsp() {
    info!("Starting language server…");
    let (service, socket) = LspService::new(CandyLanguageServer::from_client);
    Server::new(tokio::io::stdin(), tokio::io::stdout(), socket)
        .serve(service)
        .await;
}

fn init_logger() {
    let console_log = tracing_subscriber::fmt::layer()
        .compact()
        .with_span_events(FmtSpan::ENTER)
        .with_filter(filter::filter_fn(|metadata| {
            // For external packages, show only the error logs.
            metadata.level() <= &Level::ERROR
                || metadata
                    .module_path()
                    .unwrap_or_default()
                    .starts_with("candy")
        }))
        .with_filter(filter::filter_fn(level_for("candy::compiler", Level::WARN)))
        .with_filter(filter::filter_fn(level_for(
            "candy::language_server",
            Level::DEBUG,
        )))
        .with_filter(filter::filter_fn(level_for("candy::vm", Level::DEBUG)))
        .with_filter(filter::filter_fn(level_for(
            "candy::vm::heap",
            Level::DEBUG,
        )));
    tracing_subscriber::registry().with(console_log).init();
}
fn level_for(module: &'static str, level: Level) -> impl Fn(&Metadata) -> bool {
    move |metadata| {
        if metadata
            .module_path()
            .unwrap_or_default()
            .starts_with(module)
        {
            metadata.level() <= &level
        } else {
            true
        }
    }
}
<|endoftext|>


<commit_before>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;
use std::str;
use std::fmt;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug, Clone)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to
    /// [`ErrorKind`](enum.ErrorKind.html).
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Utf8Error(ref err) => write!(f, "UTF-8 conversion error at pos={}: {}", self.pos, err),
            ErrorKind::InvalidMagic => write!(f, "Invalid magic header at pos={}: Non-FBX or corrupted data?", self.pos),
            ErrorKind::Io(ref err) => write!(f, "I/O error at pos={}: {}", self.pos, err),
            ErrorKind::DataError(ref err) => write!(f, "Invalid data at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedValue(ref err) => write!(f, "Got an unexpected value at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedEof => write!(f, "Unexpected EOF at pos={}", self.pos),
            ErrorKind::Unimplemented(ref err) => write!(f, "Unimplemented feature: {}", err),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::Utf8Error(ref err) => err.description(),
            ErrorKind::InvalidMagic => "Got an invalid magic header",
            ErrorKind::Io(ref err) => err.description(),
            ErrorKind::DataError(_) => "Got an invalid data",
            ErrorKind::UnexpectedValue(_) => "Invalid value in FBX data",
            ErrorKind::UnexpectedEof => "Unexpected EOF",
            ErrorKind::Unimplemented(_) => "Attempt to use unimplemented feature",
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    Utf8Error(str::Utf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of [`DataError`](#variant.DataError).
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl Clone for ErrorKind {
    fn clone(&self) -> Self {
        use self::ErrorKind::*;
        use std::error::Error;
        match *self {
            Utf8Error(ref e) => Utf8Error(e.clone()),
            InvalidMagic => InvalidMagic,
            // `io::Error` (and an error wrapped by `io::Error`) cannot be cloned.
            Io(ref e) => Io(io::Error::new(e.kind(), e.description())),
            DataError(ref e) => DataError(e.clone()),
            UnexpectedValue(ref e) => UnexpectedValue(e.clone()),
            UnexpectedEof => UnexpectedEof,
            Unimplemented(ref e) => Unimplemented(e.clone()),
        }
    }
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::Utf8Error(err.utf8_error())
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<commit_msg>Improve `error::Error`<commit_after>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;
use std::str;
use std::fmt;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug, Clone)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to
    /// [`ErrorKind`](enum.ErrorKind.html).
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Utf8Error(ref err) => write!(f, "UTF-8 conversion error at pos={}: {}", self.pos, err),
            ErrorKind::InvalidMagic => write!(f, "Invalid magic header at pos={}: Non-FBX or corrupted data?", self.pos),
            ErrorKind::Io(ref err) => write!(f, "I/O error at pos={}: {}", self.pos, err),
            ErrorKind::DataError(ref err) => write!(f, "Invalid data at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedValue(ref err) => write!(f, "Got an unexpected value at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedEof => write!(f, "Unexpected EOF at pos={}", self.pos),
            ErrorKind::Unimplemented(ref err) => write!(f, "Unimplemented feature: {}", err),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::Utf8Error(ref err) => err.description(),
            ErrorKind::InvalidMagic => "Got an invalid magic header",
            ErrorKind::Io(ref err) => err.description(),
            ErrorKind::DataError(_) => "Got an invalid data",
            ErrorKind::UnexpectedValue(_) => "Invalid value in FBX data",
            ErrorKind::UnexpectedEof => "Unexpected EOF",
            ErrorKind::Unimplemented(_) => "Attempt to use unimplemented feature",
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        match self.kind {
            ErrorKind::Utf8Error(ref err) => Some(err as &::std::error::Error),
            ErrorKind::Io(ref err) => Some(err as &::std::error::Error),
            _ => None,
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    Utf8Error(str::Utf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of [`DataError`](#variant.DataError).
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl Clone for ErrorKind {
    fn clone(&self) -> Self {
        use self::ErrorKind::*;
        use std::error::Error;
        match *self {
            Utf8Error(ref e) => Utf8Error(e.clone()),
            InvalidMagic => InvalidMagic,
            // `io::Error` (and an error wrapped by `io::Error`) cannot be cloned.
            Io(ref e) => Io(io::Error::new(e.kind(), e.description())),
            DataError(ref e) => DataError(e.clone()),
            UnexpectedValue(ref e) => UnexpectedValue(e.clone()),
            UnexpectedEof => UnexpectedEof,
            Unimplemented(ref e) => Unimplemented(e.clone()),
        }
    }
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::Utf8Error(err.utf8_error())
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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
//
//     https://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.

use core::cell::Cell;
use kernel::common::cells::VolatileCell;
use kernel::hil::time::{self, Alarm, Frequency, Ticks};

const TIMELS0_BASE: *const Registers = 0x40540000 as *const Registers;
const TIMELS1_BASE: *const Registers = 0x40540040 as *const Registers;

pub static mut TIMELS0: Timels = Timels::new(TIMELS0_BASE);
pub static mut TIMELS1: Timels = Timels::new(TIMELS1_BASE);

struct Registers {
    pub control: VolatileCell<u32>,
    pub status: VolatileCell<u32>,
    pub load: VolatileCell<u32>,
    pub reload: VolatileCell<u32>,
    pub value: VolatileCell<u32>,
    pub step: VolatileCell<u32>,
    pub interrupt_enable: VolatileCell<u32>,
    pub interrupt_status: VolatileCell<u32>,
    pub interrupt_pending: VolatileCell<u32>,
    pub interrupt_ack: VolatileCell<u32>,
    pub interrupt_wakeup_ack: VolatileCell<u32>,
}

pub struct Timels {
    registers: *const Registers,
    client: Cell<Option<&'static dyn time::AlarmClient>>,
    now: Cell<u32>,
}

impl Timels {
    const fn new(regs: *const Registers) -> Timels {
        Timels {
            registers: regs,
            client: Cell::new(None),
            now: Cell::new(0),
        }
    }

    pub fn handle_interrupt(&self) {
        let regs = unsafe { &*self.registers };
        regs.interrupt_ack.set(1);
        regs.interrupt_wakeup_ack.set(1);
        regs.control.set(0);
        self.now.set(self.now.get().wrapping_add(regs.reload.get()));
        regs.reload.set(0);
        self.client.get().map(|client| {
            client.alarm();
        });
    }
}

pub struct Freq256Khz;

impl Frequency for Freq256Khz {
    fn frequency() -> u32 {
        256000
    }
}

impl time::Time for Timels {
    type Frequency = Freq256Khz;
    type Ticks = time::Ticks32;

    fn now(&self) -> Self::Ticks {
        let regs = unsafe { &*self.registers };
        let cur = regs.value.get();
        let reload = regs.reload.get();
        let elapsed = reload - cur;
        self.now.get().wrapping_add(elapsed).into()
    }
}

impl Alarm<'static> for Timels {
    fn set_alarm(&self, _reference: Self::Ticks, dt: Self::Ticks) {
        // TODO: This is over-simplified, as it does not account for time since
        // reference.
        let distance = dt.into_u32();
        let regs = unsafe { &*self.registers };
        regs.load.set(distance);
        regs.reload.set(distance);
        regs.interrupt_enable.set(1);
        regs.control.set(1);
    }

    fn get_alarm(&self) -> Self::Ticks {
        let regs = unsafe { &*self.registers };
        regs.reload.get().into()
    }

    fn set_alarm_client(&'static self, client: &'static dyn time::AlarmClient) {
        self.client.set(Some(client));
    }

    fn is_armed(&self) -> bool {
        let regs = unsafe { &*self.registers };
        regs.control.get() & 1 == 1 && regs.value.get() != 0
    }

    fn disarm(&self) -> kernel::ReturnCode {
        let regs = unsafe { &*self.registers };
        regs.control.set(0);
        kernel::ReturnCode::SUCCESS
    }

    fn minimum_dt(&self) -> Self::Ticks {
        // TODO: placeholder value
        1.into()
    }
}
<commit_msg>kernel: Fix set_alarm to use `reference` value.<commit_after>// Copyright 2018 Google LLC
//
// 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
//
//     https://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.

use core::cell::Cell;
use kernel::common::cells::VolatileCell;
use kernel::hil::time::{self, Alarm, Frequency, Ticks};

const TIMELS0_BASE: *const Registers = 0x40540000 as *const Registers;
const TIMELS1_BASE: *const Registers = 0x40540040 as *const Registers;

pub static mut TIMELS0: Timels = Timels::new(TIMELS0_BASE);
pub static mut TIMELS1: Timels = Timels::new(TIMELS1_BASE);

struct Registers {
    pub control: VolatileCell<u32>,
    pub status: VolatileCell<u32>,
    pub load: VolatileCell<u32>,
    pub reload: VolatileCell<u32>,
    pub value: VolatileCell<u32>,
    pub step: VolatileCell<u32>,
    pub interrupt_enable: VolatileCell<u32>,
    pub interrupt_status: VolatileCell<u32>,
    pub interrupt_pending: VolatileCell<u32>,
    pub interrupt_ack: VolatileCell<u32>,
    pub interrupt_wakeup_ack: VolatileCell<u32>,
}

pub struct Timels {
    registers: *const Registers,
    client: Cell<Option<&'static dyn time::AlarmClient>>,
    now: Cell<u32>,
}

impl Timels {
    const fn new(regs: *const Registers) -> Timels {
        Timels {
            registers: regs,
            client: Cell::new(None),
            now: Cell::new(0),
        }
    }

    pub fn handle_interrupt(&self) {
        let regs = unsafe { &*self.registers };
        regs.interrupt_ack.set(1);
        regs.interrupt_wakeup_ack.set(1);
        regs.control.set(0);
        self.now.set(self.now.get().wrapping_add(regs.reload.get()));
        regs.reload.set(0);
        self.client.get().map(|client| {
            client.alarm();
        });
    }
}

pub struct Freq256Khz;

impl Frequency for Freq256Khz {
    fn frequency() -> u32 {
        256000
    }
}

impl time::Time for Timels {
    type Frequency = Freq256Khz;
    type Ticks = time::Ticks32;

    fn now(&self) -> Self::Ticks {
        let regs = unsafe { &*self.registers };
        let cur = regs.value.get();
        let reload = regs.reload.get();
        let elapsed = reload - cur;
        self.now.get().wrapping_add(elapsed).into()
    }
}

impl Alarm<'static> for Timels {
    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
        use crate::kernel::hil::time::Time;
        let regs = unsafe { &*self.registers };

        // Before doing anything else, stop the timer so it
        // doesn't expire on us before we can reset it.
        regs.control.set(0);

        // Re-computing now() here guarantees that we see
        // what the caller saw (or later) instead of the
        // potentially outdated `self.now` value.
        let now = self.now();

        // Compute the target alarm time, but check that it's
        // not before now. If it is, set it to a minimum to
        // ensure that it actually triggers "very soon".
        let target = reference.wrapping_add(dt);

        let distance: Self::Ticks;
        if target <= now {
            distance = 1.into();
        } else {
            distance = target.wrapping_sub(now);
        }

        regs.load.set(distance.into_u32());
        regs.reload.set(distance.into_u32());
        regs.interrupt_enable.set(1);
        regs.control.set(1);
    }

    fn get_alarm(&self) -> Self::Ticks {
        let regs = unsafe { &*self.registers };
        regs.reload.get().into()
    }

    fn set_alarm_client(&'static self, client: &'static dyn time::AlarmClient) {
        self.client.set(Some(client));
    }

    fn is_armed(&self) -> bool {
        let regs = unsafe { &*self.registers };
        regs.control.get() & 1 == 1 && regs.value.get() != 0
    }

    fn disarm(&self) -> kernel::ReturnCode {
        let regs = unsafe { &*self.registers };
        regs.control.set(0);
        kernel::ReturnCode::SUCCESS
    }

    fn minimum_dt(&self) -> Self::Ticks {
        1.into()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Rendering front-end

use std::mem::size_of;
use device;
use device::BoxBlobCast;
use device::draw::CommandBuffer;
use device::shade::{ProgramInfo, ShaderSource, Vertex, Fragment, CreateShaderError};
use device::attrib::{U8, U16, U32};
use mesh;
use shade;
use shade::{Program, ShaderParam};
use state;
use target;

/// An error with an invalid texture or uniform block.
//TODO: use slices when Rust allows
#[deriving(Show)]
pub enum ParameterError {
    /// Error from a uniform value
    ErrorParamUniform(String),
    /// Error from a uniform block.
    ErrorParamBlock(String),
    /// Error from a texture.
    ErrorParamTexture(String),
    /// Error from a sampler
    ErrorParamSampler(String),
}

/// An error with a defined Mesh.
#[deriving(Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing,
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
}

/// An error that can happen when trying to draw.
#[deriving(Show)]
pub enum DrawError {
    /// Error with a program.
    ErrorProgram,
    /// Error with the program shell.
    ErrorParameter(ParameterError),
    /// Error with the mesh.
    ErrorMesh(MeshError),
    /// Error with the mesh slice
    ErrorSlice,
}

/// Program linking error
#[deriving(Clone, PartialEq, Show)]
pub enum ProgramError {
    /// Unable to compile the vertex shader
    ErrorVertex(CreateShaderError),
    /// Unable to compile the fragment shader
    ErrorFragment(CreateShaderError),
    /// Unable to link
    ErrorLink(()),
    /// Unable to connect parameters
    ErrorParameters(shade::ParameterError),
}

/// Graphics state
#[allow(dead_code)]
// This is going to be used to do minimal state transfers between draw calls. Not yet implemented!
struct State {
    frame: target::Frame,
    draw_state: state::DrawState,
}

/// Backend extension trait for convenience methods
pub trait DeviceHelper {
    /// Create a new renderer
    fn create_renderer(&mut self) -> Renderer;
    /// Create a new mesh from the given vertex data.
    /// Convenience function around `create_buffer` and `Mesh::from`.
    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>, prim_type: device::PrimitiveType) -> mesh::Mesh;
    /// Create a simple program given a vertex shader with a fragment one.
    /// The return type can not be derived from the arguments, so you need to
    /// provide it explicitly:
    ///
    /// ```
    /// let program: MyProgram = device.link_program(vs_src, fs_src).unwrap();
    /// ```
    /// Where MyProgram type is an alias to `UserProgram<L, T>` that is
    /// typically generated by the `#[shader_param(MyProgram)]` macro
    /// used on the data struct containing shader parameters.
    fn link_program<L, T: ShaderParam<L>>(&mut self, vs_src: ShaderSource,
                    fs_src: ShaderSource) -> Result<shade::UserProgram<L, T>, ProgramError>;
}

impl<D: device::Device> DeviceHelper for D {
    fn create_renderer(&mut self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.create_array_buffer(),
            common_frame_buffer: self.create_frame_buffer(),
            default_frame_buffer: device::get_main_frame_buffer(),
            //TODO: make sure this is HW default
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>, prim_type: device::PrimitiveType) -> mesh::Mesh {
        let nv = data.len();
        debug_assert!(nv < {
            use std::num::Bounded;
            let val: device::VertexCount = Bounded::max_value();
            val as uint
        });
        let buf = self.create_buffer_static(&data);
        mesh::Mesh::from::<T>(buf, nv as device::VertexCount, prim_type)
    }

    fn link_program<L, T: ShaderParam<L>>(&mut self,
                    vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<shade::UserProgram<L, T>, ProgramError> {
        let vs = match self.create_shader(Vertex, vs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorVertex(e)),
        };
        let fs = match self.create_shader(Fragment, fs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorFragment(e)),
        };
        let prog = match self.create_program([vs, fs]) {
            Ok(p) => p,
            Err(e) => return Err(ErrorLink(e)),
        };
        shade::UserProgram::connect(prog).map_err(|e| ErrorParameters(e))
    }
}

/// Renderer front-end
pub struct Renderer {
    buf: device::ActualCommandBuffer,
    common_array_buffer: Result<device::ArrayBufferHandle, ()>,
    common_frame_buffer: device::FrameBufferHandle,
    default_frame_buffer: device::FrameBufferHandle,
    state: State,
}

impl Renderer {
    /// Reset all commands for the command buffer re-usal.
    pub fn reset(&mut self) {
        self.buf.clear();
    }

    /// Get a command buffer to be submitted
    pub fn as_buffer(&self) -> &device::ActualCommandBuffer {
        &self.buf
    }

    /// Clone the renderer shared data but ignore the commands
    pub fn clone_empty(&self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.common_array_buffer,
            common_frame_buffer: self.common_frame_buffer,
            default_frame_buffer: self.default_frame_buffer,
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: device::target::ClearData, frame: &target::Frame) {
        self.bind_frame(frame);
        self.buf.call_clear(data);
    }

    /// Draw `slice` of `mesh` into `frame`, using a program shell, and a given draw state.
    pub fn draw<P: Copy + Program>(&mut self, mesh: &mesh::Mesh, slice: mesh::Slice,
                frame: &target::Frame, program: P, state: &state::DrawState)
                -> Result<(), DrawError> {
        self.bind_frame(frame);
        match self.bind_program(program) {
            Ok(_) => (),
            Err(e) => return Err(ErrorParameter(e)),
        }
        // bind fixed-function states
        self.buf.set_primitive(state.primitive);
        self.buf.set_scissor(state.scissor);
        self.buf.set_depth_stencil(state.depth, state.stencil,
            state.primitive.get_cull_mode());
        self.buf.set_blend(state.blend);
        self.buf.set_color_mask(state.color_mask);
        // bind mesh data
        match self.bind_mesh(mesh, program.get_handle().get_info()) {
            Ok(_) => (),
            Err(e) => return Err(ErrorMesh(e)),
        }
        // draw
        match slice {
            mesh::VertexSlice(start, end) => {
                self.buf.call_draw(mesh.prim_type, start, end);
            },
            mesh::IndexSlice8(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U8, start, end);
            },
            mesh::IndexSlice16(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U16, start, end);
            },
            mesh::IndexSlice32(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U32, start, end);
            },
        }
        Ok(())
    }

    /// Update a buffer with data from a vector.
    pub fn update_buffer_vec<T: Send>(&mut self, buf: device::BufferHandle<T>,
                             data: Vec<T>, offset_elements: uint) {
        let esize = size_of::<T>();
        let offset_bytes = esize * offset_elements;
        debug_assert!(data.len() * esize + offset_bytes <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<T> + Send>).cast(),
            offset_bytes
        );
    }

    /// Update a buffer with data from a single type.
    pub fn update_buffer_struct<U, T: device::Blob<U>+Send>(&mut self,
                                buf: device::BufferHandle<U>, data: T) {
        debug_assert!(size_of::<T>() <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<U> + Send>).cast(),
            0
        );
    }

    /// Update the contents of a texture.
    pub fn update_texture<T: Send>(&mut self, tex: device::TextureHandle,
                                   img: device::tex::ImageInfo, data: Vec<T>) {
        debug_assert!(tex.get_info().contains(&img));
        self.buf.update_texture(
            tex.get_info().kind,
            tex.get_name(),
            img,
            ((box data) as Box<device::Blob<T> + Send>).cast()
        );
    }

    fn bind_target(buf: &mut device::ActualCommandBuffer,
                   to: device::target::Target, plane: target::Plane) {
        match plane {
            target::PlaneEmpty =>
                buf.unbind_target(to),
            target::PlaneSurface(suf) =>
                buf.bind_target_surface(to, suf),
            target::PlaneTexture(tex, level, layer) =>
                buf.bind_target_texture(to, tex, level, layer),
        }
    }

    fn bind_frame(&mut self, frame: &target::Frame) {
        self.buf.set_viewport(device::target::Rect {
            x: 0,
            y: 0,
            w: frame.width,
            h: frame.height,
        });
        if frame.is_default() {
            // binding the default FBO, not touching our common one
            self.buf.bind_frame_buffer(self.default_frame_buffer.get_name());
        } else {
            self.buf.bind_frame_buffer(self.common_frame_buffer.get_name());
            for (i, (cur, new)) in self.state.frame.colors.iter().zip(frame.colors.iter()).enumerate() {
                if *cur != *new {
                    Renderer::bind_target(&mut self.buf, device::target::TargetColor(i as u8), *new);
                }
            }
            if self.state.frame.depth != frame.depth {
                Renderer::bind_target(&mut self.buf, device::target::TargetDepth, frame.depth);
            }
            if self.state.frame.stencil != frame.stencil {
                Renderer::bind_target(&mut self.buf, device::target::TargetStencil, frame.stencil);
            }
            self.state.frame = *frame;
        }
    }

    fn bind_program<P: Program>(&mut self, prog: P) -> Result<(), ParameterError> {
        let handle = prog.get_handle();
        self.buf.bind_program(handle.get_name());
        let pinfo = handle.get_info();
        // gather parameters
        // this is a bit ugly, not sure how to make it more sound
        let mut uniforms = Vec::from_elem(pinfo.uniforms.len(), None);
        let mut blocks   = Vec::from_elem(pinfo.blocks  .len(), None);
        let mut textures = Vec::from_elem(pinfo.textures.len(), None);
        prog.fill_params(shade::ParamValues {
            uniforms: uniforms.as_mut_slice(),
            blocks: blocks.as_mut_slice(),
            textures: textures.as_mut_slice(),
        });
        // bind uniforms
        for (var, option) in pinfo.uniforms.iter().zip(uniforms.move_iter()) {
            match option {
                Some(v) => self.buf.bind_uniform(var.location, v),
                None => return Err(ErrorParamUniform(var.name.clone())),
            }
        }
        // bind uniform blocks
        for (i, (var, option)) in pinfo.blocks.iter().zip(blocks.move_iter()).enumerate() {
            match option {
                Some(buf) => self.buf.bind_uniform_block(
                    handle.get_name(),
                    i as device::UniformBufferSlot,
                    i as device::UniformBlockIndex,
                    buf.get_name()
                ),
                None => return Err(ErrorParamBlock(var.name.clone())),
            }
        }
        // bind textures and samplers
        for (i, (var, option)) in pinfo.textures.iter().zip(textures.move_iter()).enumerate() {
            match option {
                Some((tex, sampler)) => {
                    self.buf.bind_uniform(var.location, device::shade::ValueI32(i as i32));
                    self.buf.bind_texture(i as device::TextureSlot,
                        tex.get_info().kind, tex.get_name(), sampler);
                },
                None => return Err(ErrorParamTexture(var.name.clone())),
            }
        }
        Ok(())
    }

    fn bind_mesh(&mut self, mesh: &mesh::Mesh, info: &ProgramInfo)
                 -> Result<(), MeshError> {
        // It's Ok the array buffer is not supported. If so we just ignore it.
        self.common_array_buffer.map(|ab| self.buf.bind_array_buffer(ab.get_name())).is_ok();
        for sat in info.attributes.iter() {
            match mesh.attributes.iter().find(|a| a.name.as_slice() == sat.name.as_slice()) {
                Some(vat) => match vat.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => {
                        self.buf.bind_attribute(
                            sat.location as device::AttributeSlot,
                            vat.buffer.get_name(), vat.elem_count, vat.elem_type,
                            vat.stride, vat.offset);
                    },
                    Err(_) => return Err(ErrorAttributeType)
                },
                None => return Err(ErrorAttributeMissing)
            }
        }
        Ok(())
    }
}
<commit_msg>Add name of attribute to ErrorAttributeMissing<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Rendering front-end

use std::mem::size_of;
use device;
use device::BoxBlobCast;
use device::draw::CommandBuffer;
use device::shade::{ProgramInfo, ShaderSource, Vertex, Fragment, CreateShaderError};
use device::attrib::{U8, U16, U32};
use mesh;
use shade;
use shade::{Program, ShaderParam};
use state;
use target;

/// An error with an invalid texture or uniform block.
//TODO: use slices when Rust allows
#[deriving(Show)]
pub enum ParameterError {
    /// Error from a uniform value
    ErrorParamUniform(String),
    /// Error from a uniform block.
    ErrorParamBlock(String),
    /// Error from a texture.
    ErrorParamTexture(String),
    /// Error from a sampler
    ErrorParamSampler(String),
}

/// An error with a defined Mesh.
#[deriving(Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
}

/// An error that can happen when trying to draw.
#[deriving(Show)]
pub enum DrawError {
    /// Error with a program.
    ErrorProgram,
    /// Error with the program shell.
    ErrorParameter(ParameterError),
    /// Error with the mesh.
    ErrorMesh(MeshError),
    /// Error with the mesh slice
    ErrorSlice,
}

/// Program linking error
#[deriving(Clone, PartialEq, Show)]
pub enum ProgramError {
    /// Unable to compile the vertex shader
    ErrorVertex(CreateShaderError),
    /// Unable to compile the fragment shader
    ErrorFragment(CreateShaderError),
    /// Unable to link
    ErrorLink(()),
    /// Unable to connect parameters
    ErrorParameters(shade::ParameterError),
}

/// Graphics state
#[allow(dead_code)]
// This is going to be used to do minimal state transfers between draw calls. Not yet implemented!
struct State {
    frame: target::Frame,
    draw_state: state::DrawState,
}

/// Backend extension trait for convenience methods
pub trait DeviceHelper {
    /// Create a new renderer
    fn create_renderer(&mut self) -> Renderer;
    /// Create a new mesh from the given vertex data.
    /// Convenience function around `create_buffer` and `Mesh::from`.
    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>, prim_type: device::PrimitiveType) -> mesh::Mesh;
    /// Create a simple program given a vertex shader with a fragment one.
    /// The return type can not be derived from the arguments, so you need to
    /// provide it explicitly:
    ///
    /// ```
    /// let program: MyProgram = device.link_program(vs_src, fs_src).unwrap();
    /// ```
    /// Where MyProgram type is an alias to `UserProgram<L, T>` that is
    /// typically generated by the `#[shader_param(MyProgram)]` macro
    /// used on the data struct containing shader parameters.
    fn link_program<L, T: ShaderParam<L>>(&mut self, vs_src: ShaderSource,
                    fs_src: ShaderSource) -> Result<shade::UserProgram<L, T>, ProgramError>;
}

impl<D: device::Device> DeviceHelper for D {
    fn create_renderer(&mut self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.create_array_buffer(),
            common_frame_buffer: self.create_frame_buffer(),
            default_frame_buffer: device::get_main_frame_buffer(),
            //TODO: make sure this is HW default
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>, prim_type: device::PrimitiveType) -> mesh::Mesh {
        let nv = data.len();
        debug_assert!(nv < {
            use std::num::Bounded;
            let val: device::VertexCount = Bounded::max_value();
            val as uint
        });
        let buf = self.create_buffer_static(&data);
        mesh::Mesh::from::<T>(buf, nv as device::VertexCount, prim_type)
    }

    fn link_program<L, T: ShaderParam<L>>(&mut self,
                    vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<shade::UserProgram<L, T>, ProgramError> {
        let vs = match self.create_shader(Vertex, vs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorVertex(e)),
        };
        let fs = match self.create_shader(Fragment, fs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorFragment(e)),
        };
        let prog = match self.create_program([vs, fs]) {
            Ok(p) => p,
            Err(e) => return Err(ErrorLink(e)),
        };
        shade::UserProgram::connect(prog).map_err(|e| ErrorParameters(e))
    }
}

/// Renderer front-end
pub struct Renderer {
    buf: device::ActualCommandBuffer,
    common_array_buffer: Result<device::ArrayBufferHandle, ()>,
    common_frame_buffer: device::FrameBufferHandle,
    default_frame_buffer: device::FrameBufferHandle,
    state: State,
}

impl Renderer {
    /// Reset all commands for the command buffer re-usal.
    pub fn reset(&mut self) {
        self.buf.clear();
    }

    /// Get a command buffer to be submitted
    pub fn as_buffer(&self) -> &device::ActualCommandBuffer {
        &self.buf
    }

    /// Clone the renderer shared data but ignore the commands
    pub fn clone_empty(&self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.common_array_buffer,
            common_frame_buffer: self.common_frame_buffer,
            default_frame_buffer: self.default_frame_buffer,
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: device::target::ClearData, frame: &target::Frame) {
        self.bind_frame(frame);
        self.buf.call_clear(data);
    }

    /// Draw `slice` of `mesh` into `frame`, using a program shell, and a given draw state.
    pub fn draw<P: Copy + Program>(&mut self, mesh: &mesh::Mesh, slice: mesh::Slice,
                frame: &target::Frame, program: P, state: &state::DrawState)
                -> Result<(), DrawError> {
        self.bind_frame(frame);
        match self.bind_program(program) {
            Ok(_) => (),
            Err(e) => return Err(ErrorParameter(e)),
        }
        // bind fixed-function states
        self.buf.set_primitive(state.primitive);
        self.buf.set_scissor(state.scissor);
        self.buf.set_depth_stencil(state.depth, state.stencil,
            state.primitive.get_cull_mode());
        self.buf.set_blend(state.blend);
        self.buf.set_color_mask(state.color_mask);
        // bind mesh data
        match self.bind_mesh(mesh, program.get_handle().get_info()) {
            Ok(_) => (),
            Err(e) => return Err(ErrorMesh(e)),
        }
        // draw
        match slice {
            mesh::VertexSlice(start, end) => {
                self.buf.call_draw(mesh.prim_type, start, end);
            },
            mesh::IndexSlice8(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U8, start, end);
            },
            mesh::IndexSlice16(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U16, start, end);
            },
            mesh::IndexSlice32(buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(mesh.prim_type, U32, start, end);
            },
        }
        Ok(())
    }

    /// Update a buffer with data from a vector.
    pub fn update_buffer_vec<T: Send>(&mut self, buf: device::BufferHandle<T>,
                             data: Vec<T>, offset_elements: uint) {
        let esize = size_of::<T>();
        let offset_bytes = esize * offset_elements;
        debug_assert!(data.len() * esize + offset_bytes <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<T> + Send>).cast(),
            offset_bytes
        );
    }

    /// Update a buffer with data from a single type.
    pub fn update_buffer_struct<U, T: device::Blob<U>+Send>(&mut self,
                                buf: device::BufferHandle<U>, data: T) {
        debug_assert!(size_of::<T>() <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<U> + Send>).cast(),
            0
        );
    }

    /// Update the contents of a texture.
    pub fn update_texture<T: Send>(&mut self, tex: device::TextureHandle,
                                   img: device::tex::ImageInfo, data: Vec<T>) {
        debug_assert!(tex.get_info().contains(&img));
        self.buf.update_texture(
            tex.get_info().kind,
            tex.get_name(),
            img,
            ((box data) as Box<device::Blob<T> + Send>).cast()
        );
    }

    fn bind_target(buf: &mut device::ActualCommandBuffer,
                   to: device::target::Target, plane: target::Plane) {
        match plane {
            target::PlaneEmpty =>
                buf.unbind_target(to),
            target::PlaneSurface(suf) =>
                buf.bind_target_surface(to, suf),
            target::PlaneTexture(tex, level, layer) =>
                buf.bind_target_texture(to, tex, level, layer),
        }
    }

    fn bind_frame(&mut self, frame: &target::Frame) {
        self.buf.set_viewport(device::target::Rect {
            x: 0,
            y: 0,
            w: frame.width,
            h: frame.height,
        });
        if frame.is_default() {
            // binding the default FBO, not touching our common one
            self.buf.bind_frame_buffer(self.default_frame_buffer.get_name());
        } else {
            self.buf.bind_frame_buffer(self.common_frame_buffer.get_name());
            for (i, (cur, new)) in self.state.frame.colors.iter().zip(frame.colors.iter()).enumerate() {
                if *cur != *new {
                    Renderer::bind_target(&mut self.buf, device::target::TargetColor(i as u8), *new);
                }
            }
            if self.state.frame.depth != frame.depth {
                Renderer::bind_target(&mut self.buf, device::target::TargetDepth, frame.depth);
            }
            if self.state.frame.stencil != frame.stencil {
                Renderer::bind_target(&mut self.buf, device::target::TargetStencil, frame.stencil);
            }
            self.state.frame = *frame;
        }
    }

    fn bind_program<P: Program>(&mut self, prog: P) -> Result<(), ParameterError> {
        let handle = prog.get_handle();
        self.buf.bind_program(handle.get_name());
        let pinfo = handle.get_info();
        // gather parameters
        // this is a bit ugly, not sure how to make it more sound
        let mut uniforms = Vec::from_elem(pinfo.uniforms.len(), None);
        let mut blocks   = Vec::from_elem(pinfo.blocks  .len(), None);
        let mut textures = Vec::from_elem(pinfo.textures.len(), None);
        prog.fill_params(shade::ParamValues {
            uniforms: uniforms.as_mut_slice(),
            blocks: blocks.as_mut_slice(),
            textures: textures.as_mut_slice(),
        });
        // bind uniforms
        for (var, option) in pinfo.uniforms.iter().zip(uniforms.move_iter()) {
            match option {
                Some(v) => self.buf.bind_uniform(var.location, v),
                None => return Err(ErrorParamUniform(var.name.clone())),
            }
        }
        // bind uniform blocks
        for (i, (var, option)) in pinfo.blocks.iter().zip(blocks.move_iter()).enumerate() {
            match option {
                Some(buf) => self.buf.bind_uniform_block(
                    handle.get_name(),
                    i as device::UniformBufferSlot,
                    i as device::UniformBlockIndex,
                    buf.get_name()
                ),
                None => return Err(ErrorParamBlock(var.name.clone())),
            }
        }
        // bind textures and samplers
        for (i, (var, option)) in pinfo.textures.iter().zip(textures.move_iter()).enumerate() {
            match option {
                Some((tex, sampler)) => {
                    self.buf.bind_uniform(var.location, device::shade::ValueI32(i as i32));
                    self.buf.bind_texture(i as device::TextureSlot,
                        tex.get_info().kind, tex.get_name(), sampler);
                },
                None => return Err(ErrorParamTexture(var.name.clone())),
            }
        }
        Ok(())
    }

    fn bind_mesh(&mut self, mesh: &mesh::Mesh, info: &ProgramInfo)
                 -> Result<(), MeshError> {
        // It's Ok the array buffer is not supported. If so we just ignore it.
        self.common_array_buffer.map(|ab| self.buf.bind_array_buffer(ab.get_name())).is_ok();
        for sat in info.attributes.iter() {
            match mesh.attributes.iter().find(|a| a.name.as_slice() == sat.name.as_slice()) {
                Some(vat) => match vat.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => {
                        self.buf.bind_attribute(
                            sat.location as device::AttributeSlot,
                            vat.buffer.get_name(), vat.elem_count, vat.elem_type,
                            vat.stride, vat.offset);
                    },
                    Err(_) => return Err(ErrorAttributeType)
                },
                None => return Err(ErrorAttributeMissing(sat.name.clone()))
            }
        }
        Ok(())
    }
}
<|endoftext|>