<commit_before>use crate::config::Config;
use crate::database::{CppDatabaseItem, Database};
use crate::workspace::Workspace;
use crate::{
    cpp_checker, cpp_explicit_xstructors, cpp_ffi_generator, cpp_parser, cpp_template_instantiator,
    crate_writer, rust_generator, type_allocation_places,
};
use itertools::Itertools;
use log::{error, info, trace};
use ritual_common::errors::{bail, err_msg, format_err, Result, ResultExt};
use ritual_common::utils::{run_command, MapIfOk};
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> impl Iterator<Item = &Database> {
        once(&self.current_database as &_).chain(self.dep_databases.iter())
    }
    pub fn all_items(&self) -> impl Iterator<Item = &CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items().iter())
    }
}

struct ProcessingStep {
    name: String,
    function: Box<dyn Fn(&mut ProcessorData<'_>) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let mut s = ProcessingSteps {
            all_steps: Vec::new(),
            main_procedure: Vec::new(),
        };

        let push_cpp_post_processing = |s: &mut Self| {
            s.push("add_explicit_xstructors", cpp_explicit_xstructors::run);
            s.push(
                "set_allocation_places",
                type_allocation_places::set_allocation_places,
            );
            s.push(
                "find_template_instantiations",
                cpp_template_instantiator::find_template_instantiations,
            );
            s.push(
                "instantiate_templates",
                cpp_template_instantiator::instantiate_templates,
            );
            s.push("cpp_ffi_generator", cpp_ffi_generator::run);
            s.push("cpp_checker", cpp_checker::run);
        };

        s.push("cpp_parser", cpp_parser::run);
        push_cpp_post_processing(&mut s);
        s.push("cpp_parser_stage2", cpp_parser::parse_generated_items);
        push_cpp_post_processing(&mut s);
        s.push("rust_generator", rust_generator::run);
        s.push("crate_writer", crate_writer::run);
        s.push("build_crate", build_crate);

        s.add_custom("clear_ffi", |data| {
            data.current_database.clear_ffi();
            Ok(())
        });
        s.add_custom("clear_rust_info", |data| {
            data.current_database.clear_rust_info();
            Ok(())
        });

        s.add_custom(
            "suggest_allocation_places",
            type_allocation_places::suggest_allocation_places,
        );
        s
    }
}

impl ProcessingSteps {
    pub fn add_after<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        after: &[&str],
        name: &str,
        func: F,
    ) -> Result<()> {
        let indexes = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| format_err!("requested step not found: {}", s))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, name.to_string());
        self.all_steps.push(ProcessingStep::new(name, func));
        Ok(())
    }

    pub fn push<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        name: &str,
        func: F,
    ) {
        self.main_procedure.push(name.to_string());
        self.all_steps.push(ProcessingStep::new(name, func));
    }

    pub fn add_custom<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        name: &str,
        func: F,
    ) {
        self.all_steps.push(ProcessingStep::new(name, func));
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        name: S,
        function: F,
    ) -> Self {
        ProcessingStep {
            name: name.into(),
            function: Box::new(function),
        }
    }
}

fn build_crate(data: &mut ProcessorData<'_>) -> Result<()> {
    data.workspace.update_cargo_toml()?;
    let path = data.workspace.path();
    let crate_name = data.config.crate_properties().name();
    //run_command(Command::new("cargo").arg("update").current_dir(path))?;

    for cargo_cmd in &["build", "test", "doc"] {
        run_command(
            Command::new("cargo")
                .arg(cargo_cmd)
                .arg("-p")
                .arg(crate_name)
                .current_dir(path),
        )?;
    }
    Ok(())
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef<'_>) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef<'_>) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    current_database.set_crate_version(config.crate_properties().version().to_string());

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else if step_name.starts_with("from:") {
            let start_step = &step_name["from:".len()..];
            let start_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == start_step)
                .ok_or_else(|| format_err!("requested step not found: {}", start_step))?;
            config.processing_steps().main_procedure[start_index..].to_vec()
        } else if step_name.starts_with("until:") {
            let end_step = &step_name["until:".len()..];
            let end_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == end_step)
                .ok_or_else(|| format_err!("requested step not found: {}", end_step))?;
            config.processing_steps().main_procedure[..end_index].to_vec()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            let started_time = Instant::now();

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }

            trace!(
                "Step '{}' completed in {:?}",
                step.name,
                started_time.elapsed()
            );
        }
    }

    for database in dependent_cpp_crates {
        workspace.put_crate(database);
    }

    if current_database.is_modified() {
        info!("Saving data");
    }

    workspace.put_crate(current_database);
    workspace.save_data()?;

    steps_result
}
<commit_msg>fix stage2 step names<commit_after>use crate::config::Config;
use crate::database::{CppDatabaseItem, Database};
use crate::workspace::Workspace;
use crate::{
    cpp_checker, cpp_explicit_xstructors, cpp_ffi_generator, cpp_parser, cpp_template_instantiator,
    crate_writer, rust_generator, type_allocation_places,
};
use itertools::Itertools;
use log::{error, info, trace};
use ritual_common::errors::{bail, err_msg, format_err, Result, ResultExt};
use ritual_common::utils::{run_command, MapIfOk};
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> impl Iterator<Item = &Database> {
        once(&self.current_database as &_).chain(self.dep_databases.iter())
    }
    pub fn all_items(&self) -> impl Iterator<Item = &CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items().iter())
    }
}

struct ProcessingStep {
    name: String,
    function: Box<dyn Fn(&mut ProcessorData<'_>) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let mut s = ProcessingSteps {
            all_steps: Vec::new(),
            main_procedure: Vec::new(),
        };

        let push_cpp_post_processing = |s: &mut Self, suffix: &str| {
            s.push(
                &format!("add_explicit_xstructors{}", suffix),
                cpp_explicit_xstructors::run,
            );
            s.push(
                &format!("set_allocation_places{}", suffix),
                type_allocation_places::set_allocation_places,
            );
            s.push(
                &format!("find_template_instantiations{}", suffix),
                cpp_template_instantiator::find_template_instantiations,
            );
            s.push(
                &format!("instantiate_templates{}", suffix),
                cpp_template_instantiator::instantiate_templates,
            );
            s.push(
                &format!("cpp_ffi_generator{}", suffix),
                cpp_ffi_generator::run,
            );
            s.push(&format!("cpp_checker{}", suffix), cpp_checker::run);
        };

        s.push("cpp_parser", cpp_parser::run);
        push_cpp_post_processing(&mut s, "");
        s.push("cpp_parser_stage2", cpp_parser::parse_generated_items);
        push_cpp_post_processing(&mut s, "_stage2");
        s.push("rust_generator", rust_generator::run);
        s.push("crate_writer", crate_writer::run);
        s.push("build_crate", build_crate);

        s.add_custom("clear_ffi", |data| {
            data.current_database.clear_ffi();
            Ok(())
        });
        s.add_custom("clear_rust_info", |data| {
            data.current_database.clear_rust_info();
            Ok(())
        });

        s.add_custom(
            "suggest_allocation_places",
            type_allocation_places::suggest_allocation_places,
        );
        s
    }
}

impl ProcessingSteps {
    pub fn add_after<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        after: &[&str],
        name: &str,
        func: F,
    ) -> Result<()> {
        let indexes = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| format_err!("requested step not found: {}", s))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, name.to_string());
        self.all_steps.push(ProcessingStep::new(name, func));
        Ok(())
    }

    pub fn push<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        name: &str,
        func: F,
    ) {
        self.main_procedure.push(name.to_string());
        self.all_steps.push(ProcessingStep::new(name, func));
    }

    pub fn add_custom<F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        &mut self,
        name: &str,
        func: F,
    ) {
        self.all_steps.push(ProcessingStep::new(name, func));
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData<'_>) -> Result<()>>(
        name: S,
        function: F,
    ) -> Self {
        ProcessingStep {
            name: name.into(),
            function: Box::new(function),
        }
    }
}

fn build_crate(data: &mut ProcessorData<'_>) -> Result<()> {
    data.workspace.update_cargo_toml()?;
    let path = data.workspace.path();
    let crate_name = data.config.crate_properties().name();
    //run_command(Command::new("cargo").arg("update").current_dir(path))?;

    for cargo_cmd in &["build", "test", "doc"] {
        run_command(
            Command::new("cargo")
                .arg(cargo_cmd)
                .arg("-p")
                .arg(crate_name)
                .current_dir(path),
        )?;
    }
    Ok(())
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef<'_>) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef<'_>) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    current_database.set_crate_version(config.crate_properties().version().to_string());

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else if step_name.starts_with("from:") {
            let start_step = &step_name["from:".len()..];
            let start_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == start_step)
                .ok_or_else(|| format_err!("requested step not found: {}", start_step))?;
            config.processing_steps().main_procedure[start_index..].to_vec()
        } else if step_name.starts_with("until:") {
            let end_step = &step_name["until:".len()..];
            let end_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == end_step)
                .ok_or_else(|| format_err!("requested step not found: {}", end_step))?;
            config.processing_steps().main_procedure[..end_index].to_vec()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            let started_time = Instant::now();

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }

            trace!(
                "Step '{}' completed in {:?}",
                step.name,
                started_time.elapsed()
            );
        }
    }

    for database in dependent_cpp_crates {
        workspace.put_crate(database);
    }

    if current_database.is_modified() {
        info!("Saving data");
    }

    workspace.put_crate(current_database);
    workspace.save_data()?;

    steps_result
}
<|endoftext|>


<commit_before>use sys::{VALUE, Qnil};
use super::{UncheckedValue, CheckResult, CheckedValue, ToRust, ToRuby};

impl<T> UncheckedValue<Option<T>> for VALUE where VALUE: UncheckedValue<T> {
    fn to_checked(self) -> CheckResult<Option<T>> {
        if unsafe { self == Qnil } {
            Ok(unsafe { CheckedValue::new(self) })
        } else {
            match UncheckedValue::<T>::to_checked(self) {
                Ok(_) => Ok(unsafe { CheckedValue::new(self) }),
                Err(e) => Err(e)
            }
        }
    }
}

impl<T> ToRust<Option<T>> for CheckedValue<Option<T>> where CheckedValue<T>: ToRust<T> {
    fn to_rust(self) -> Option<T> {
        if unsafe { self.inner == Qnil } {
            None
        } else {
            let checked: CheckedValue<T> = unsafe { CheckedValue::new(self.inner) };
            Some(checked.to_rust())
        }
    }
}

impl<T> ToRuby for Option<T> where T: ToRuby {
    fn to_ruby(self) -> VALUE {
        match self {
            Some(value) => value.to_ruby(),
            None => unsafe { Qnil }
        }
    }
}
<commit_msg>Prefer `Option` combinator over `match`.<commit_after>use sys::{VALUE, Qnil};
use super::{UncheckedValue, CheckResult, CheckedValue, ToRust, ToRuby};

impl<T> UncheckedValue<Option<T>> for VALUE where VALUE: UncheckedValue<T> {
    fn to_checked(self) -> CheckResult<Option<T>> {
        if unsafe { self == Qnil } {
            Ok(unsafe { CheckedValue::new(self) })
        } else {
            UncheckedValue::<T>::to_checked(self)
                .map(|_| unsafe { CheckedValue::new(self) })
        }
    }
}

impl<T> ToRust<Option<T>> for CheckedValue<Option<T>> where CheckedValue<T>: ToRust<T> {
    fn to_rust(self) -> Option<T> {
        if unsafe { self.inner == Qnil } {
            None
        } else {
            let checked: CheckedValue<T> = unsafe { CheckedValue::new(self.inner) };
            Some(checked.to_rust())
        }
    }
}

impl<T> ToRuby for Option<T> where T: ToRuby {
    fn to_ruby(self) -> VALUE {
        match self {
            Some(value) => value.to_ruby(),
            None => unsafe { Qnil }
        }
    }
}
<|endoftext|>


<commit_before>// Rust-natord: Natural ordering for Rust.
// Copyright (c) 2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

#![crate_name = "natord"]
#![crate_type = "lib"]

#![feature(macro_rules)]

/*!
 * Natural ordering for Rust. This allows for the comparison like this:
 *
 * ~~~~ {.rust}
 * let mut files = vec!("rfc2086.txt", "rfc822.txt", "rfc1.txt");
 * files.sort_by(|&a, &b| natord::compare(a, b));
 * assert_eq!(files.as_slice(), ["rfc1.txt", "rfc822.txt", "rfc2086.txt"].as_slice());
 * ~~~~
 *
 * There are multiple natural ordering algorithms available.
 * This version of natural ordering is inspired by
 * [Martin Pool's `strnatcmp.c`](http://sourcefrog.net/projects/natsort/).
 */

/// Compares two iterators of "characters" possibly containing "digits".
/// The natural ordering can be customized with the following parameters:
///
/// * `skip` returns true if the "character" does not affect the comparison,
///   other than splitting two consecutive digits.
/// * `cmp` compares two "characters", assuming that they are not "digits".
/// * `to_digit` converts a "character" into a "digit" if possible. The digit of zero is special.
pub fn compare_iter<T, L: Iterator<T>, R: Iterator<T>>(left: L, right: R,
                                                       skip: |&T| -> bool,
                                                       cmp: |&T, &T| -> Ordering,
                                                       to_digit: |&T| -> Option<int>) -> Ordering {
    let mut left = left.fuse();
    let mut right = right.fuse();

    let mut l;
    let mut r;
    let mut ll;
    let mut rr;

    macro_rules! read_left(
        () => ({
            l = left.next();
            ll = l.as_ref().and_then(|v| to_digit(v));
        })
    )

    macro_rules! read_right(
        () => ({
            r = right.next();
            rr = r.as_ref().and_then(|v| to_digit(v));
        })
    )

    macro_rules! return_unless_equal(
        ($ord:expr) => (
            match $ord {
                Equal => {}
                lastcmp => return lastcmp,
            }
        )
    )

    read_left!();
    read_right!();
    'nondigits: loop {
        // skip preceding whitespaces
        while l.as_ref().map_or(false, |c| skip(c)) { read_left!(); }
        while r.as_ref().map_or(false, |c| skip(c)) { read_right!(); }

        match (l, r) {
            (Some(l_), Some(r_)) => match (ll, rr) {
                (Some(ll_), Some(rr_)) => {
                    if ll_ == 0 || rr_ == 0 {
                        // left-aligned matching. (`015` < `12`)
                        return_unless_equal!(ll_.cmp(&rr_));
                        'digits: loop {
                            read_left!();
                            read_right!();
                            match (ll, rr) {
                                (Some(ll_), Some(rr_)) => return_unless_equal!(ll_.cmp(&rr_)),
                                (Some(_), None) => return Greater,
                                (None, Some(_)) => return Less,
                                (None, None) => break 'digits,
                            }
                        }
                    } else {
                        // right-aligned matching. (`15` < `123`)
                        let mut lastcmp = ll_.cmp(&rr_);
                        'digits: loop {
                            read_left!();
                            read_right!();
                            match (ll, rr) {
                                (Some(ll_), Some(rr_)) => {
                                    // `lastcmp` is only used when there are the same number of
                                    // digits, so we only update it.
                                    if lastcmp == Equal { lastcmp = ll_.cmp(&rr_); }
                                }
                                (Some(_), None) => return Greater,
                                (None, Some(_)) => return Less,
                                (None, None) => break 'digits,
                            }
                        }
                        return_unless_equal!(lastcmp);
                    }
                    continue 'nondigits; // do not read from the iterators again
                },
                (_, _) => return_unless_equal!(cmp(&l_, &r_)),
            },
            (Some(_), None) => return Greater,
            (None, Some(_)) => return Less,
            (None, None) => return Equal,
        }

        read_left!();
        read_right!();
    }
}

/// Compares two strings case-sensitively.
/// It skips any Unicode whitespaces and handles a series of decimal digits.
pub fn compare(left: &str, right: &str) -> Ordering {
    compare_iter(left.chars(), right.chars(),
                 |&c| c.is_whitespace(),
                 |&l, &r| l.cmp(&r),
                 |&c| c.to_digit(10).map(|v| v as int))
}

/// Compares two strings case-insensitively.
/// It skips any Unicode whitespaces and handles a series of decimal digits.
pub fn compare_ignore_case(left: &str, right: &str) -> Ordering {
    // XXX what we really want is a case folding!
    // Unicode case folding can be done iteratively, but currently we don't have them in stdlib.
    compare_iter(left.chars(), right.chars(),
                 |&c| c.is_whitespace(),
                 |&l, &r| l.to_lowercase().cmp(&r.to_lowercase()),
                 |&c| c.to_digit(10).map(|v| v as int))
}

#[cfg(test)]
mod tests {
    use super::compare;

    fn check_total_order(strs: &[&str]) {
        fn ordering_to_op(ord: Ordering) -> &'static str {
            match ord {
                Greater => ">",
                Equal => "=",
                Less => "<",
            }
        }

        for (i, &x) in strs.iter().enumerate() {
            for (j, &y) in strs.iter().enumerate() {
                assert!(compare(x, y) == i.cmp(&j),
                        "expected x {} y, returned x {} y (where x = `{}`, y = `{}`)",
                        ordering_to_op(i.cmp(&j)), ordering_to_op(compare(x, y)), x, y);
            }
        }
    }

    #[test]
    fn test_numeric() {
        check_total_order(&["a", "a0", "a1", "a1a", "a1b", "a2", "a10", "a20"]);
    }

    #[test]
    fn test_multiple_parts() {
        check_total_order(&["x2-g8", "x2-y7", "x2-y8", "x8-y8"]);
    }

    #[test]
    fn test_leading_zeroes() {
        check_total_order(&["1.001", "1.002", "1.010", "1.02", "1.1", "1.3"]);
    }

    #[test]
    fn test_longer() {
        check_total_order(&[
            "1-02",
            "1-2",
            "1-20",
            "10-20",
            "fred",
            "jane",
            "pic1",
            "pic2",
            "pic2a",
            "pic3",
            "pic4",
            "pic4   alpha",
            "pic 4 else",
            "pic4  last",
            "pic5",
            "pic5.07",
            "pic5.08",
            "pic5.13",
            "pic5.113",
            "pic 5 something",
            "pic 6",
            "pic   7",
            "pic100",
            "pic100a",
            "pic120",
            "pic121",
            "pic2000",
            "tom",
            "x2-g8",
            "x2-y7",
            "x2-y8",
            "x8-y8",
        ]);
    }
}
<commit_msg>Fix for changes to macro syntax in latest Rust<commit_after>// Rust-natord: Natural ordering for Rust.
// Copyright (c) 2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

#![crate_name = "natord"]
#![crate_type = "lib"]

#![feature(macro_rules)]

/*!
 * Natural ordering for Rust. This allows for the comparison like this:
 *
 * ~~~~ {.rust}
 * let mut files = vec!("rfc2086.txt", "rfc822.txt", "rfc1.txt");
 * files.sort_by(|&a, &b| natord::compare(a, b));
 * assert_eq!(files.as_slice(), ["rfc1.txt", "rfc822.txt", "rfc2086.txt"].as_slice());
 * ~~~~
 *
 * There are multiple natural ordering algorithms available.
 * This version of natural ordering is inspired by
 * [Martin Pool's `strnatcmp.c`](http://sourcefrog.net/projects/natsort/).
 */

/// Compares two iterators of "characters" possibly containing "digits".
/// The natural ordering can be customized with the following parameters:
///
/// * `skip` returns true if the "character" does not affect the comparison,
///   other than splitting two consecutive digits.
/// * `cmp` compares two "characters", assuming that they are not "digits".
/// * `to_digit` converts a "character" into a "digit" if possible. The digit of zero is special.
pub fn compare_iter<T, L: Iterator<T>, R: Iterator<T>>(left: L, right: R,
                                                       skip: |&T| -> bool,
                                                       cmp: |&T, &T| -> Ordering,
                                                       to_digit: |&T| -> Option<int>) -> Ordering {
    let mut left = left.fuse();
    let mut right = right.fuse();

    let mut l;
    let mut r;
    let mut ll;
    let mut rr;

    macro_rules! read_left(
        () => ({
            l = left.next();
            ll = l.as_ref().and_then(|v| to_digit(v));
        })
    );

    macro_rules! read_right(
        () => ({
            r = right.next();
            rr = r.as_ref().and_then(|v| to_digit(v));
        })
    );

    macro_rules! return_unless_equal(
        ($ord:expr) => (
            match $ord {
                Equal => {}
                lastcmp => return lastcmp,
            }
        )
    );

    read_left!();
    read_right!();
    'nondigits: loop {
        // skip preceding whitespaces
        while l.as_ref().map_or(false, |c| skip(c)) { read_left!(); }
        while r.as_ref().map_or(false, |c| skip(c)) { read_right!(); }

        match (l, r) {
            (Some(l_), Some(r_)) => match (ll, rr) {
                (Some(ll_), Some(rr_)) => {
                    if ll_ == 0 || rr_ == 0 {
                        // left-aligned matching. (`015` < `12`)
                        return_unless_equal!(ll_.cmp(&rr_));
                        'digits: loop {
                            read_left!();
                            read_right!();
                            match (ll, rr) {
                                (Some(ll_), Some(rr_)) => return_unless_equal!(ll_.cmp(&rr_)),
                                (Some(_), None) => return Greater,
                                (None, Some(_)) => return Less,
                                (None, None) => break 'digits,
                            }
                        }
                    } else {
                        // right-aligned matching. (`15` < `123`)
                        let mut lastcmp = ll_.cmp(&rr_);
                        'digits: loop {
                            read_left!();
                            read_right!();
                            match (ll, rr) {
                                (Some(ll_), Some(rr_)) => {
                                    // `lastcmp` is only used when there are the same number of
                                    // digits, so we only update it.
                                    if lastcmp == Equal { lastcmp = ll_.cmp(&rr_); }
                                }
                                (Some(_), None) => return Greater,
                                (None, Some(_)) => return Less,
                                (None, None) => break 'digits,
                            }
                        }
                        return_unless_equal!(lastcmp);
                    }
                    continue 'nondigits; // do not read from the iterators again
                },
                (_, _) => return_unless_equal!(cmp(&l_, &r_)),
            },
            (Some(_), None) => return Greater,
            (None, Some(_)) => return Less,
            (None, None) => return Equal,
        }

        read_left!();
        read_right!();
    }
}

/// Compares two strings case-sensitively.
/// It skips any Unicode whitespaces and handles a series of decimal digits.
pub fn compare(left: &str, right: &str) -> Ordering {
    compare_iter(left.chars(), right.chars(),
                 |&c| c.is_whitespace(),
                 |&l, &r| l.cmp(&r),
                 |&c| c.to_digit(10).map(|v| v as int))
}

/// Compares two strings case-insensitively.
/// It skips any Unicode whitespaces and handles a series of decimal digits.
pub fn compare_ignore_case(left: &str, right: &str) -> Ordering {
    // XXX what we really want is a case folding!
    // Unicode case folding can be done iteratively, but currently we don't have them in stdlib.
    compare_iter(left.chars(), right.chars(),
                 |&c| c.is_whitespace(),
                 |&l, &r| l.to_lowercase().cmp(&r.to_lowercase()),
                 |&c| c.to_digit(10).map(|v| v as int))
}

#[cfg(test)]
mod tests {
    use super::compare;

    fn check_total_order(strs: &[&str]) {
        fn ordering_to_op(ord: Ordering) -> &'static str {
            match ord {
                Greater => ">",
                Equal => "=",
                Less => "<",
            }
        }

        for (i, &x) in strs.iter().enumerate() {
            for (j, &y) in strs.iter().enumerate() {
                assert!(compare(x, y) == i.cmp(&j),
                        "expected x {} y, returned x {} y (where x = `{}`, y = `{}`)",
                        ordering_to_op(i.cmp(&j)), ordering_to_op(compare(x, y)), x, y);
            }
        }
    }

    #[test]
    fn test_numeric() {
        check_total_order(&["a", "a0", "a1", "a1a", "a1b", "a2", "a10", "a20"]);
    }

    #[test]
    fn test_multiple_parts() {
        check_total_order(&["x2-g8", "x2-y7", "x2-y8", "x8-y8"]);
    }

    #[test]
    fn test_leading_zeroes() {
        check_total_order(&["1.001", "1.002", "1.010", "1.02", "1.1", "1.3"]);
    }

    #[test]
    fn test_longer() {
        check_total_order(&[
            "1-02",
            "1-2",
            "1-20",
            "10-20",
            "fred",
            "jane",
            "pic1",
            "pic2",
            "pic2a",
            "pic3",
            "pic4",
            "pic4   alpha",
            "pic 4 else",
            "pic4  last",
            "pic5",
            "pic5.07",
            "pic5.08",
            "pic5.13",
            "pic5.113",
            "pic 5 something",
            "pic 6",
            "pic   7",
            "pic100",
            "pic100a",
            "pic120",
            "pic121",
            "pic2000",
            "tom",
            "x2-g8",
            "x2-y7",
            "x2-y8",
            "x8-y8",
        ]);
    }
}
<|endoftext|>


<commit_before>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::hint;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completely fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        Spinlock {
            queue: AtomicUsize::new(0),
            dequeue: AtomicUsize::new(1),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            hint::spin_loop();
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task id by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

pub type MovableMutex = Mutex;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { inner: Spinlock::new(MutexInner::new()) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<commit_msg>If the thread does not get the lock in the short term, yield the CPU<commit_after>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::hint;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completely fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        Spinlock {
            queue: AtomicUsize::new(0),
            dequeue: AtomicUsize::new(1),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        let mut counter: u16 = 0;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            counter = counter + 1;
            if counter < 100 {
                hint::spin_loop();
            } else {
                counter = 0;
                unsafe {
                    abi::yield_now();
                }
            }
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task id by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

pub type MovableMutex = Mutex;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { inner: Spinlock::new(MutexInner::new()) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeap_(@{
    head: E,
    rest: @List<PairingHeap<E>>
  })
}

pub trait Heap<E: Copy Eq Ord> {
  // I would really love for these to return Heaps but my knowledge
  // of Rust is too limited to make that work.
  pure fn is_empty() -> bool;
  pure fn insert(elem: E) -> PairingHeap<E>;
  pure fn find_min() -> (Option<E>, PairingHeap<E>);
  pure fn delete_min() -> (Option<E>, PairingHeap<E>);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  return Empty_;
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  return PairingHeap_(@{
    head: initial_value,
    rest: @Nil
  });
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeap_(heapA), PairingHeap_(heapB)) => {
        return (heapA.head == heapB.head) && (heapA.rest == heapB.rest);
      }
      //(Empty_, PairingHeap_(_)) => {false} // why are these unreachable?
      //(PairingHeap_(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty() -> bool {
    match self {
      Empty_ => { return true; }
      _ => {return false; }
    };
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    return self.merge(PairingHeap(e));
  }

  pure fn find_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => { return (None, self); }
      p@PairingHeap_(heap) => { return (Some(heap.head), p); }
    }
  }

  // Deletes the minimum item without returning it
  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeap_(heap) => {(Some(heap.head), self.merge_pairs(heap.rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { return b; }
      (a, Empty_) => { return a; }
      (x@PairingHeap_(heapA), y@PairingHeap_(heapB)) => {
        if (heapA.head.le(&heapB.head)) {
          return PairingHeap_(@{
            head: heapA.head,
            rest: @Cons(y, heapA.rest)
          });
        } else {
          return PairingHeap_(@{
            head: heapB.head,
            rest: @Cons(x, heapB.rest)
          });
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<commit_msg>improved documentation, testing find_min<commit_after>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeap_(@{
    head: E,
    rest: @List<PairingHeap<E>>
  })
}

pub trait Heap<E: Copy Eq Ord> {
  // I would really love for these to return Heaps but my knowledge
  // of Rust is too limited to make that work.

  // returns true if the Heap is empty.
  pure fn is_empty() -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> PairingHeap<E>;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, PairingHeap<E>);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  return Empty_;
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  return PairingHeap_(@{
    head: initial_value,
    rest: @Nil
  });
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeap_(heapA), PairingHeap_(heapB)) => {
        return (heapA.head == heapB.head) && (heapA.rest == heapB.rest);
      }
      //(Empty_, PairingHeap_(_)) => {false} // why are these unreachable?
      //(PairingHeap_(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty() -> bool {
    match self {
      Empty_ => { return true; }
      _ => {return false; }
    };
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    return self.merge(PairingHeap(e));
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeap_(heap) => { Some(heap.head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeap_(heap) => {(Some(heap.head), self.merge_pairs(heap.rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { return b; }
      (a, Empty_) => { return a; }
      (x@PairingHeap_(heapA), y@PairingHeap_(heapB)) => {
        if (heapA.head.le(&heapB.head)) {
          return PairingHeap_(@{
            head: heapA.head,
            rest: @Cons(y, heapA.rest)
          });
        } else {
          return PairingHeap_(@{
            head: heapB.head,
            rest: @Cons(x, heapB.rest)
          });
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<|endoftext|>


<commit_before>extern crate rs6502;
extern crate sdl2;
extern crate vm;

mod ship;

use std::path::Path;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::TextureQuery;

use rs6502::{Assembler, Cpu};
use vm::VirtualMachine;

const FPS_STEP: u32 = 1000 / 60;

fn main() {

    let bytecode = assemble("level.asm");
    let cpu = init_cpu(&bytecode);
    let mut vm = VirtualMachine::new(cpu, 0xC000, 150);

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", 400, 720)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();
    let ship_flame_texture = renderer.load_texture(Path::new("ship-flame.png")).unwrap();

    let mut win_font = ttf_context.load_font(Path::new("FantasqueSansMono-Bold.ttf"), 64).unwrap();
    win_font.set_style(sdl2::ttf::STYLE_BOLD);

    let mut finish_font = ttf_context.load_font(Path::new("FantasqueSansMono-Bold.ttf"), 64)
        .unwrap();
    finish_font.set_style(sdl2::ttf::STYLE_BOLD);

    let win_message_surface = win_font.render("PASSED")
        .blended(Color::RGBA(0, 0, 0, 255))
        .unwrap();
    let finish_banner_surface = finish_font.render("FINISH")
        .blended_wrapped(Color::RGBA(0, 0, 0, 255), 56)
        .unwrap();
    let win_message_texture = renderer.create_texture_from_surface(&win_message_surface)
        .unwrap();
    let finish_banner_texture = renderer.create_texture_from_surface(&finish_banner_surface)
        .unwrap();
    let mut events = sdl_context.event_pump().unwrap();

    let mut level_complete = false;
    let mut ship = ship::Ship::new(ship_texture, ship_flame_texture);
    let mut last_fps = 0;
    let mut monitor_last = 0;
    let TextureQuery { width: win_width, height: win_height, .. } = win_message_texture.query();
    let TextureQuery { width: finish_width, height: finish_height, .. } =
        finish_banner_texture.query();

    'running: loop {

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Up), .. } => {
                    vm.cpu.memory[0x04] = 38;
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Down), .. } => {
                    vm.cpu.memory[0x04] = 40;
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Up), .. } => {
                    vm.cpu.memory[0x04] = 0;
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Down), .. } => {
                    vm.cpu.memory[0x04] = 0;
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        if !level_complete {
            vm.try_execute_command();
            ship.process(&vm.cpu.memory[..]);

            // Pull the ship back so it can't go past a certain spot
            if ship.y <= 0x190 && ship.y >= 0x100 && vm.cpu.memory[0x04] != 0 {
                vm.cpu.memory[0x02] = 0x90;
                vm.cpu.memory[0x03] = 0x01;
            }
        }

        let now = sdl_context.timer().unwrap().ticks();
        let delta = now - last_fps;
        if delta < FPS_STEP {
            sdl_context.timer().unwrap().delay(FPS_STEP - delta);
        } else {
            vm.cycle();
            if !vm.cpu.flags.interrupt_disabled {
                renderer.clear();
                renderer.set_draw_color(Color::RGB(0, 144, 192));
                renderer.fill_rect(Rect::new(0, 0, 400, 120)).unwrap();
                if level_complete {
                    renderer.set_draw_color(Color::RGB(0, 255, 0));
                    renderer.fill_rect(Rect::new(0, 300, 400, 120)).unwrap();
                    renderer.copy(&win_message_texture,
                              None,
                              Some(Rect::new(100, 330, win_width, win_height)))
                        .unwrap();
                }
                renderer.set_draw_color(Color::RGB(0, 0, 0));
                renderer.copy(&finish_banner_texture,
                          None,
                          Some(Rect::new(100, 25, finish_width, finish_height)))
                    .unwrap();
                if vm.cpu.memory[0x07] > 0 {
                    ship.render_flame(&mut renderer);
                }
                ship.render(&mut renderer);
                if ship.y <= 0x8C {
                    level_complete = true;
                }
                renderer.present();
                last_fps = now;
            }
        }

        // Dump the CPU memory at 1 second intervals if the monitor is enabled
        let delta = now - monitor_last;
        if delta > 1000 && vm.monitor.enabled {
            vm.dump_memory();
            monitor_last = now;
        }
    }
}

fn assemble<P>(path: P) -> Vec<u8>
    where P: AsRef<Path>
{
    let mut assembler = Assembler::new();
    assembler.assemble_file(path, 0xC000).unwrap()
}

fn init_cpu(bytecode: &[u8]) -> Cpu {
    let mut cpu = Cpu::new();
    cpu.load(&bytecode[..], None).unwrap();
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x00] = 0x90;
    cpu.memory[0x02] = 0xFF;
    cpu.memory[0x03] = 0x01;
    cpu.memory[0x05] = 0x05;
    cpu.memory[0x06] = 0x00;

    cpu
}<commit_msg>Add window dimension constants<commit_after>extern crate rs6502;
extern crate sdl2;
extern crate vm;

mod ship;

use std::path::Path;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::TextureQuery;

use rs6502::{Assembler, Cpu};
use vm::VirtualMachine;

const FPS_STEP: u32 = 1000 / 60;
const WINDOW_WIDTH: u32 = 400;
const WINDOW_HEIGHT: u32 = 720;

fn main() {

    let bytecode = assemble("level.asm");
    let cpu = init_cpu(&bytecode);
    let mut vm = VirtualMachine::new(cpu, 0xC000, 150);

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", WINDOW_WIDTH, WINDOW_HEIGHT)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();
    let ship_flame_texture = renderer.load_texture(Path::new("ship-flame.png")).unwrap();

    let mut win_font = ttf_context.load_font(Path::new("FantasqueSansMono-Bold.ttf"), 64).unwrap();
    win_font.set_style(sdl2::ttf::STYLE_BOLD);

    let mut finish_font = ttf_context.load_font(Path::new("FantasqueSansMono-Bold.ttf"), 64)
        .unwrap();
    finish_font.set_style(sdl2::ttf::STYLE_BOLD);

    let win_message_surface = win_font.render("PASSED")
        .blended(Color::RGBA(0, 0, 0, 255))
        .unwrap();
    let finish_banner_surface = finish_font.render("FINISH")
        .blended_wrapped(Color::RGBA(0, 0, 0, 255), 56)
        .unwrap();
    let win_message_texture = renderer.create_texture_from_surface(&win_message_surface)
        .unwrap();
    let finish_banner_texture = renderer.create_texture_from_surface(&finish_banner_surface)
        .unwrap();
    let mut events = sdl_context.event_pump().unwrap();

    let mut level_complete = false;
    let mut ship = ship::Ship::new(ship_texture, ship_flame_texture);
    let mut last_fps = 0;
    let mut monitor_last = 0;
    let TextureQuery { width: win_width, height: win_height, .. } = win_message_texture.query();
    let TextureQuery { width: finish_width, height: finish_height, .. } =
        finish_banner_texture.query();

    'running: loop {

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Up), .. } => {
                    vm.cpu.memory[0x04] = 38;
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Down), .. } => {
                    vm.cpu.memory[0x04] = 40;
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Up), .. } => {
                    vm.cpu.memory[0x04] = 0;
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Down), .. } => {
                    vm.cpu.memory[0x04] = 0;
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        if !level_complete {
            vm.try_execute_command();
            ship.process(&vm.cpu.memory[..]);

            // Pull the ship back so it can't go past a certain spot
            if ship.y <= 0x190 && ship.y >= 0x100 && vm.cpu.memory[0x04] != 0 {
                vm.cpu.memory[0x02] = 0x90;
                vm.cpu.memory[0x03] = 0x01;
            }
        }

        let now = sdl_context.timer().unwrap().ticks();
        let delta = now - last_fps;
        if delta < FPS_STEP {
            sdl_context.timer().unwrap().delay(FPS_STEP - delta);
        } else {
            vm.cycle();
            if !vm.cpu.flags.interrupt_disabled {
                renderer.clear();
                renderer.set_draw_color(Color::RGB(0, 144, 192));
                renderer.fill_rect(Rect::new(0, 0, WINDOW_WIDTH, 120)).unwrap();
                if level_complete {
                    renderer.set_draw_color(Color::RGB(0, 255, 0));
                    renderer.fill_rect(Rect::new(0, 300, WINDOW_WIDTH, 120)).unwrap();
                    renderer.copy(&win_message_texture,
                              None,
                              Some(Rect::new(100, 330, win_width, win_height)))
                        .unwrap();
                }
                renderer.set_draw_color(Color::RGB(0, 0, 0));
                renderer.copy(&finish_banner_texture,
                          None,
                          Some(Rect::new(100, 25, finish_width, finish_height)))
                    .unwrap();
                if vm.cpu.memory[0x07] > 0 {
                    ship.render_flame(&mut renderer);
                }
                ship.render(&mut renderer);
                if ship.y <= 0x8C {
                    level_complete = true;
                }
                renderer.present();
                last_fps = now;
            }
        }

        // Dump the CPU memory at 1 second intervals if the monitor is enabled
        let delta = now - monitor_last;
        if delta > 1000 && vm.monitor.enabled {
            vm.dump_memory();
            monitor_last = now;
        }
    }
}

fn assemble<P>(path: P) -> Vec<u8>
    where P: AsRef<Path>
{
    let mut assembler = Assembler::new();
    assembler.assemble_file(path, 0xC000).unwrap()
}

fn init_cpu(bytecode: &[u8]) -> Cpu {
    let mut cpu = Cpu::new();
    cpu.load(&bytecode[..], None).unwrap();
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x00] = 0x90;
    cpu.memory[0x02] = 0xFF;
    cpu.memory[0x03] = 0x01;
    cpu.memory[0x05] = 0x05;
    cpu.memory[0x06] = 0x00;

    cpu
}<|endoftext|>


<commit_before>use value::{Id, Value, Tuple, Relation, ToTuple};
use index::{Index};
use query::{Ref, ConstraintOp, Constraint, Source, Clause, Query};
use flow::{Changes, View, Union, Node, FlowState, Flow};

use std::collections::{HashMap, BitSet};
use std::cell::{RefCell, RefMut};
use std::num::ToPrimitive;

#[derive(Clone, Debug)]
pub struct World {
    pub views: HashMap<Id, RefCell<Relation>>,
}

impl World {
    pub fn get_or_create<Id: ToString>(&mut self, id: Id) -> &mut RefCell<Relation> {
        self.views.entry(id.to_string()).or_insert_with(|| RefCell::new(Index::new()))
    }

    pub fn change(&mut self, changes: Changes) {
        for (view_id, changes) in changes.into_iter() {
            self.get_or_create(&view_id).borrow_mut().change(changes)
        }
    }

    fn view<Id: ToString>(&self, id: Id) -> ::std::cell::Ref<Relation> {
        self.views.get(&id.to_string()).expect(&id.to_string()).borrow()
    }

    fn view_mut<Id: ToString>(&self, id: Id) -> RefMut<Relation> {
        self.views.get(&id.to_string()).expect(&id.to_string()).borrow_mut()
    }
}

impl Index<Tuple> {
    pub fn find_all(&self, ix: usize, value: &Value) -> Vec<&Tuple> {
        self.iter().filter(|t| &t[ix] == value).collect()
    }

    pub fn find_one(&self, ix: usize, value: &Value) -> Option<&Tuple> {
        match &*self.find_all(ix, value) {
            [t] => Some(t),
            _ => None,
        }
    }
}

// TODO
// check schema, field, view
// check schemas on every view
// check every view has a schema
// check every non-empty view is a view with kind=input
// fill in missing views with empty indexes
// check upstream etc are empty
// gather function refs
// poison rows in rounds until changes stop
//   foreign keys don't exist or are poisoned
//   ixes are not 0-n

static COMPILER_VIEWS: [&'static str; 7] =
["view", "source", "constraint", "view-mapping", "field-mapping", "schedule", "upstream"];

static VIEW_ID: usize = 0;
static VIEW_SCHEMA: usize = 1;
static VIEW_KIND: usize = 2;

static FIELD_SCHEMA: usize = 0;
static FIELD_IX: usize = 1;
static FIELD_ID: usize = 2;

static SOURCE_VIEW: usize = 0;
static SOURCE_IX: usize = 1;
static SOURCE_ID: usize = 2;
static SOURCE_DATA: usize = 3;
static SOURCE_ACTION: usize = 4;

static CONSTRAINT_LEFT: usize = 0;
static CONSTRAINT_OP: usize = 1;
static CONSTRAINT_RIGHT: usize = 2;

static VIEWMAPPING_ID: usize = 0;
static VIEWMAPPING_SOURCEVIEW: usize = 1;
static VIEWMAPPING_SINKVIEW: usize = 2;

static FIELDMAPPING_VIEWMAPPING: usize = 0;
static FIELDMAPPING_SOURCEFIELD: usize = 1;
static FIELDMAPPING_SOURCECOLUMN: usize = 2;
static FIELDMAPPING_SINKFIELD: usize = 3;

static SCHEDULE_IX: usize = 0;
static SCHEDULE_VIEW: usize = 1;

static UPSTREAM_DOWNSTREAM: usize = 0;
static UPSTREAM_IX: usize = 1;
static UPSTREAM_UPSTREAM: usize = 2;

fn create_upstream(world: &mut World) {
    let mut upstream = world.view_mut("upstream");
    for view in world.view("view").iter() {
        let downstream_id = &view[VIEW_ID];
        let kind = &view[VIEW_KIND];
        let mut ix = 0.0;
        match &*kind.to_string() {
            "input" => (),
            "query" => {
                for source in world.view("source").find_all(SOURCE_VIEW, downstream_id) {
                    let data = &source[SOURCE_DATA];
                    if &*data[0].to_string() == "view"  {
                        let upstream_id = &data[1];
                        upstream.insert((downstream_id.clone(), ix, upstream_id.clone()).to_tuple());
                        ix += 1.0;
                    }
                }
            }
            "union" => {
                for view_mapping in world.view("view-mapping").find_all(VIEWMAPPING_SINKVIEW, downstream_id) {
                    let upstream_id = &view_mapping[VIEWMAPPING_SOURCEVIEW];
                    upstream.insert((downstream_id.clone(), ix, upstream_id.clone()).to_tuple());
                    ix += 1.0;
                }
            }
            other => panic!("Unknown view kind: {}", other)
        }
    }
}

fn create_schedule(world: &mut World) {
    // TODO actually schedule sensibly
    // TODO warn about cycles through aggregates
    let mut schedule = world.view_mut("schedule");
    let mut ix = 0.0;
    for view in world.view("view").iter() {
        let view_id = &view[VIEW_ID];
        schedule.insert((ix, view_id.clone()).to_tuple());
        ix += 1.0;
    }
}

fn get_view_ix(world: &World, view_id: &Value) -> usize {
    let schedule = world.view("schedule").find_one(SCHEDULE_VIEW, view_id).unwrap().clone();
    schedule[SCHEDULE_IX].to_usize().unwrap()
}

fn get_source_ix(world: &World, source_id: &Value) -> usize {
    let source = world.view("source").find_one(SOURCE_ID, source_id).unwrap().clone();
    source[SOURCE_IX].to_usize().unwrap()
}

fn get_field_ix(world: &World, field_id: &Value) -> usize {
    let field = world.view("field").find_one(FIELD_ID, field_id).unwrap().clone();
    field[FIELD_IX].to_usize().unwrap()
}

fn get_num_fields(world: &World, view_id: &Value) -> usize {
    let view = world.view("view").find_one(VIEW_ID, view_id).unwrap().clone();
    let schema_id = &view[VIEW_SCHEMA];
    world.view("field").find_all(FIELD_SCHEMA, schema_id).len()
}

fn create_constraint(world: &World, constraint: &Vec<Value>) -> Constraint {
    let my_column = &constraint[CONSTRAINT_LEFT][2];
    let op = match &*constraint[CONSTRAINT_OP].to_string() {
          "<" => ConstraintOp::LT,
          "<=" => ConstraintOp::LTE,
          "=" => ConstraintOp::EQ,
          "!=" => ConstraintOp::NEQ,
          ">" => ConstraintOp::GT,
          ">=" => ConstraintOp::GTE,
          other => panic!("Unknown constraint op: {}", other),
    };
    let constraint_right = &constraint[CONSTRAINT_RIGHT];
    let other_ref = match &*constraint_right[0].to_string() {
        "column" => {
            let other_source_id = &constraint_right[1];
            let other_field_id = &constraint_right[2];
            let other_source_ix = get_source_ix(world, other_source_id);
            let other_field_ix = get_field_ix(world, other_field_id);
            Ref::Value{
                clause: other_source_ix,
                column: other_field_ix,
            }
        }
        "constant" => {
            let value = constraint_right[1].clone();
            Ref::Constant{
                value: value,
            }
        }
        other => panic!("Unknown ref kind: {}", other)
    };
    Constraint{
        my_column: my_column.to_usize().unwrap(),
        op: op,
        other_ref: other_ref,
    }
}

fn create_clause(world: &World, source: &Vec<Value>) -> Clause {
    let source_view_id = &source[SOURCE_VIEW];
    let source_data = &source[SOURCE_DATA];
    if source_data[0].to_string() == "view" {
        let other_view_id = &source_data[1];
        let upstreams = world.view("upstream");
        let upstream = upstreams.iter().filter(|upstream| {
            (upstream[UPSTREAM_DOWNSTREAM] == *source_view_id) &&
            (upstream[UPSTREAM_UPSTREAM] == *other_view_id)
        }).next().unwrap();
        let other_view_ix = &upstream[UPSTREAM_IX];
        let constraints = world.view("constraint").iter().filter(|constraint| {
            constraint[CONSTRAINT_LEFT][2] == *other_view_id
        }).map(|constraint| {
            create_constraint(world, constraint)
        }).collect::<Vec<_>>();
        match &*source[SOURCE_ACTION].to_string() {
            "get-tuple" => {
                Clause::Tuple(Source{
                    relation: other_view_ix.to_usize().unwrap(),
                    constraints: constraints,
                })
            }
            "get-relation" => {
                Clause::Relation(Source{
                    relation: other_view_ix.to_usize().unwrap(),
                    constraints: constraints,
                })
            }
            other => panic!("Unknown view action: {}", other)
        }
    } else {
        panic!("Can't compile functions yet")
    }

}

fn create_query(world: &World, view_id: &Value) -> Query {
    // arrives in ix order
    let clauses = world.view("source").find_all(SOURCE_VIEW, view_id).iter().map(|source|
        create_clause(world, source)
        ).collect();
    Query{clauses: clauses}
}

fn create_union(world: &World, view_id: &Value) -> Union {
    let num_sink_fields = get_num_fields(world, view_id);
    let mut view_mappings = Vec::new();
    for upstream in world.view("upstream").find_all(UPSTREAM_DOWNSTREAM, view_id) { // arrives in ix order
        let source_view_id = &upstream[UPSTREAM_UPSTREAM];
        let view_mapping = world.view("view-mapping").find_one(VIEWMAPPING_SOURCEVIEW, source_view_id).unwrap().clone();
        let view_mapping_id = &view_mapping[VIEWMAPPING_ID];
        let invalid = ::std::usize::MAX;
        let mut field_mappings = vec![(invalid, invalid); num_sink_fields];
        for field_mapping in world.view("field-mapping").find_all(FIELDMAPPING_VIEWMAPPING, &view_mapping_id) {
            let source_field_id = &field_mapping[FIELDMAPPING_SOURCEFIELD];
            let source_field_ix = get_field_ix(world, source_field_id);
            let source_column_id = &field_mapping[FIELDMAPPING_SOURCECOLUMN];
            let source_column_ix = get_field_ix(world, source_column_id);
            let sink_field_id = &field_mapping[FIELDMAPPING_SINKFIELD];
            let sink_field_ix = get_field_ix(world, sink_field_id);
            field_mappings[sink_field_ix] = (source_field_ix, source_column_ix);
        }
        let num_source_fields = get_num_fields(world, source_view_id);
        view_mappings.push((num_source_fields, field_mappings));
    }
    Union{mappings: view_mappings}
}

fn create_node(world: &World, view_id: &Value, view_kind: &Value) -> Node {
    let view = match &*view_kind.to_string() {
        "input" => View::Input,
        "query" => View::Query(create_query(world, view_id)),
        "union" => View::Union(create_union(world, view_id)),
        other => panic!("Unknown view kind: {}", other)
    };
    let upstream = world.view("upstream").find_all(UPSTREAM_DOWNSTREAM, view_id).iter().map(|upstream| {
        get_view_ix(world, &upstream[UPSTREAM_UPSTREAM])
    }).collect(); // arrives in ix order so it will match the arg order selected by create_query/union
    let downstream = world.view("upstream").find_all(UPSTREAM_UPSTREAM, view_id).iter().map(|upstream| {
        get_view_ix(world, &upstream[UPSTREAM_DOWNSTREAM])
    }).collect();
    Node{
        id: view_id.to_string(),
        view: view,
        upstream: upstream,
        downstream: downstream,
    }
}

fn create_flow(world: &World) -> Flow {
    let mut nodes = Vec::new();
    for schedule in world.view("schedule").iter() { // arrives in ix order
        let view_id = &schedule[SCHEDULE_VIEW];
        let view = world.view("view").find_one(VIEW_ID, view_id).unwrap().clone();
        let view_kind = &view[VIEW_KIND];
        let node = create_node(world, view_id, view_kind);
        nodes.push(node);
    }
    Flow{
        nodes: nodes
    }
}

fn create_flow_state(world: &World, flow: &Flow) -> FlowState {
    let mut dirty = BitSet::new();
    let mut outputs = Vec::new();
    for (ix, node) in flow.nodes.iter().enumerate() {
        outputs.push(world.views.get(&node.id).map_or_else(
            || RefCell::new(Index::new()),
            |r| r.clone()
            ));
        match node.view {
            View::Input => (),
            _ => {dirty.insert(ix);},
        }
    }
    FlowState{
        dirty: dirty,
        outputs: outputs
    }
}

pub fn compile(world: &mut World) -> (Flow, FlowState) {
    for view_id in COMPILER_VIEWS.iter() {
        world.get_or_create(view_id);
    }
    create_upstream(world);
    create_schedule(world);
    let flow = create_flow(world);
    let flow_state = create_flow_state(world, &flow);
    (flow, flow_state)
}<commit_msg>Better error messages for find_one<commit_after>use value::{Id, Value, Tuple, Relation, ToTuple};
use index::{Index};
use query::{Ref, ConstraintOp, Constraint, Source, Clause, Query};
use flow::{Changes, View, Union, Node, FlowState, Flow};

use std::collections::{HashMap, BitSet};
use std::cell::{RefCell, RefMut};
use std::num::ToPrimitive;

#[derive(Clone, Debug)]
pub struct World {
    pub views: HashMap<Id, RefCell<Relation>>,
}

impl World {
    pub fn get_or_create<Id: ToString>(&mut self, id: Id) -> &mut RefCell<Relation> {
        self.views.entry(id.to_string()).or_insert_with(|| RefCell::new(Index::new()))
    }

    pub fn change(&mut self, changes: Changes) {
        for (view_id, changes) in changes.into_iter() {
            self.get_or_create(&view_id).borrow_mut().change(changes)
        }
    }

    fn view<Id: ToString>(&self, id: Id) -> ::std::cell::Ref<Relation> {
        self.views.get(&id.to_string()).expect(&id.to_string()).borrow()
    }

    fn view_mut<Id: ToString>(&self, id: Id) -> RefMut<Relation> {
        self.views.get(&id.to_string()).expect(&id.to_string()).borrow_mut()
    }
}

impl Index<Tuple> {
    pub fn find_all(&self, ix: usize, value: &Value) -> Vec<&Tuple> {
        self.iter().filter(|t| &t[ix] == value).collect()
    }

    pub fn find_one(&self, ix: usize, value: &Value) -> &Tuple {
        match &*self.find_all(ix, value) {
            [] => panic!("No tuples with tuple[{}] = {:?}", ix, value),
            [t] => t,
            _ => panic!("Multiple tuples with tuple[{}] = {:?}", ix, value),
        }
    }
}

// TODO
// check schema, field, view
// check schemas on every view
// check every view has a schema
// check every non-empty view is a view with kind=input
// fill in missing views with empty indexes
// check upstream etc are empty
// gather function refs
// poison rows in rounds until changes stop
//   foreign keys don't exist or are poisoned
//   ixes are not 0-n

static COMPILER_VIEWS: [&'static str; 7] =
["view", "source", "constraint", "view-mapping", "field-mapping", "schedule", "upstream"];

static VIEW_ID: usize = 0;
static VIEW_SCHEMA: usize = 1;
static VIEW_KIND: usize = 2;

static FIELD_SCHEMA: usize = 0;
static FIELD_IX: usize = 1;
static FIELD_ID: usize = 2;

static SOURCE_VIEW: usize = 0;
static SOURCE_IX: usize = 1;
static SOURCE_ID: usize = 2;
static SOURCE_DATA: usize = 3;
static SOURCE_ACTION: usize = 4;

static CONSTRAINT_LEFT: usize = 0;
static CONSTRAINT_OP: usize = 1;
static CONSTRAINT_RIGHT: usize = 2;

static VIEWMAPPING_ID: usize = 0;
static VIEWMAPPING_SOURCEVIEW: usize = 1;
static VIEWMAPPING_SINKVIEW: usize = 2;

static FIELDMAPPING_VIEWMAPPING: usize = 0;
static FIELDMAPPING_SOURCEFIELD: usize = 1;
static FIELDMAPPING_SOURCECOLUMN: usize = 2;
static FIELDMAPPING_SINKFIELD: usize = 3;

static SCHEDULE_IX: usize = 0;
static SCHEDULE_VIEW: usize = 1;

static UPSTREAM_DOWNSTREAM: usize = 0;
static UPSTREAM_IX: usize = 1;
static UPSTREAM_UPSTREAM: usize = 2;

fn create_upstream(world: &mut World) {
    let mut upstream = world.view_mut("upstream");
    for view in world.view("view").iter() {
        let downstream_id = &view[VIEW_ID];
        let kind = &view[VIEW_KIND];
        let mut ix = 0.0;
        match &*kind.to_string() {
            "input" => (),
            "query" => {
                for source in world.view("source").find_all(SOURCE_VIEW, downstream_id) {
                    let data = &source[SOURCE_DATA];
                    if &*data[0].to_string() == "view"  {
                        let upstream_id = &data[1];
                        upstream.insert((downstream_id.clone(), ix, upstream_id.clone()).to_tuple());
                        ix += 1.0;
                    }
                }
            }
            "union" => {
                for view_mapping in world.view("view-mapping").find_all(VIEWMAPPING_SINKVIEW, downstream_id) {
                    let upstream_id = &view_mapping[VIEWMAPPING_SOURCEVIEW];
                    upstream.insert((downstream_id.clone(), ix, upstream_id.clone()).to_tuple());
                    ix += 1.0;
                }
            }
            other => panic!("Unknown view kind: {}", other)
        }
    }
}

fn create_schedule(world: &mut World) {
    // TODO actually schedule sensibly
    // TODO warn about cycles through aggregates
    let mut schedule = world.view_mut("schedule");
    let mut ix = 0.0;
    for view in world.view("view").iter() {
        let view_id = &view[VIEW_ID];
        schedule.insert((ix, view_id.clone()).to_tuple());
        ix += 1.0;
    }
}

fn get_view_ix(world: &World, view_id: &Value) -> usize {
    let schedule = world.view("schedule").find_one(SCHEDULE_VIEW, view_id).clone();
    schedule[SCHEDULE_IX].to_usize().unwrap()
}

fn get_source_ix(world: &World, source_id: &Value) -> usize {
    let source = world.view("source").find_one(SOURCE_ID, source_id).clone();
    source[SOURCE_IX].to_usize().unwrap()
}

fn get_field_ix(world: &World, field_id: &Value) -> usize {
    let field = world.view("field").find_one(FIELD_ID, field_id).clone();
    field[FIELD_IX].to_usize().unwrap()
}

fn get_num_fields(world: &World, view_id: &Value) -> usize {
    let view = world.view("view").find_one(VIEW_ID, view_id).clone();
    let schema_id = &view[VIEW_SCHEMA];
    world.view("field").find_all(FIELD_SCHEMA, schema_id).len()
}

fn create_constraint(world: &World, constraint: &Vec<Value>) -> Constraint {
    let my_column = &constraint[CONSTRAINT_LEFT][2];
    let op = match &*constraint[CONSTRAINT_OP].to_string() {
          "<" => ConstraintOp::LT,
          "<=" => ConstraintOp::LTE,
          "=" => ConstraintOp::EQ,
          "!=" => ConstraintOp::NEQ,
          ">" => ConstraintOp::GT,
          ">=" => ConstraintOp::GTE,
          other => panic!("Unknown constraint op: {}", other),
    };
    let constraint_right = &constraint[CONSTRAINT_RIGHT];
    let other_ref = match &*constraint_right[0].to_string() {
        "column" => {
            let other_source_id = &constraint_right[1];
            let other_field_id = &constraint_right[2];
            let other_source_ix = get_source_ix(world, other_source_id);
            let other_field_ix = get_field_ix(world, other_field_id);
            Ref::Value{
                clause: other_source_ix,
                column: other_field_ix,
            }
        }
        "constant" => {
            let value = constraint_right[1].clone();
            Ref::Constant{
                value: value,
            }
        }
        other => panic!("Unknown ref kind: {}", other)
    };
    Constraint{
        my_column: my_column.to_usize().unwrap(),
        op: op,
        other_ref: other_ref,
    }
}

fn create_clause(world: &World, source: &Vec<Value>) -> Clause {
    let source_view_id = &source[SOURCE_VIEW];
    let source_data = &source[SOURCE_DATA];
    if source_data[0].to_string() == "view" {
        let other_view_id = &source_data[1];
        let upstreams = world.view("upstream");
        let upstream = upstreams.iter().filter(|upstream| {
            (upstream[UPSTREAM_DOWNSTREAM] == *source_view_id) &&
            (upstream[UPSTREAM_UPSTREAM] == *other_view_id)
        }).next().unwrap();
        let other_view_ix = &upstream[UPSTREAM_IX];
        let constraints = world.view("constraint").iter().filter(|constraint| {
            constraint[CONSTRAINT_LEFT][2] == *other_view_id
        }).map(|constraint| {
            create_constraint(world, constraint)
        }).collect::<Vec<_>>();
        match &*source[SOURCE_ACTION].to_string() {
            "get-tuple" => {
                Clause::Tuple(Source{
                    relation: other_view_ix.to_usize().unwrap(),
                    constraints: constraints,
                })
            }
            "get-relation" => {
                Clause::Relation(Source{
                    relation: other_view_ix.to_usize().unwrap(),
                    constraints: constraints,
                })
            }
            other => panic!("Unknown view action: {}", other)
        }
    } else {
        panic!("Can't compile functions yet")
    }

}

fn create_query(world: &World, view_id: &Value) -> Query {
    // arrives in ix order
    let clauses = world.view("source").find_all(SOURCE_VIEW, view_id).iter().map(|source|
        create_clause(world, source)
        ).collect();
    Query{clauses: clauses}
}

fn create_union(world: &World, view_id: &Value) -> Union {
    let num_sink_fields = get_num_fields(world, view_id);
    let mut view_mappings = Vec::new();
    for upstream in world.view("upstream").find_all(UPSTREAM_DOWNSTREAM, view_id) { // arrives in ix order
        let source_view_id = &upstream[UPSTREAM_UPSTREAM];
        let view_mapping = world.view("view-mapping").find_one(VIEWMAPPING_SOURCEVIEW, source_view_id).clone();
        let view_mapping_id = &view_mapping[VIEWMAPPING_ID];
        let invalid = ::std::usize::MAX;
        let mut field_mappings = vec![(invalid, invalid); num_sink_fields];
        for field_mapping in world.view("field-mapping").find_all(FIELDMAPPING_VIEWMAPPING, &view_mapping_id) {
            let source_field_id = &field_mapping[FIELDMAPPING_SOURCEFIELD];
            let source_field_ix = get_field_ix(world, source_field_id);
            let source_column_id = &field_mapping[FIELDMAPPING_SOURCECOLUMN];
            let source_column_ix = get_field_ix(world, source_column_id);
            let sink_field_id = &field_mapping[FIELDMAPPING_SINKFIELD];
            let sink_field_ix = get_field_ix(world, sink_field_id);
            field_mappings[sink_field_ix] = (source_field_ix, source_column_ix);
        }
        let num_source_fields = get_num_fields(world, source_view_id);
        view_mappings.push((num_source_fields, field_mappings));
    }
    Union{mappings: view_mappings}
}

fn create_node(world: &World, view_id: &Value, view_kind: &Value) -> Node {
    let view = match &*view_kind.to_string() {
        "input" => View::Input,
        "query" => View::Query(create_query(world, view_id)),
        "union" => View::Union(create_union(world, view_id)),
        other => panic!("Unknown view kind: {}", other)
    };
    let upstream = world.view("upstream").find_all(UPSTREAM_DOWNSTREAM, view_id).iter().map(|upstream| {
        get_view_ix(world, &upstream[UPSTREAM_UPSTREAM])
    }).collect(); // arrives in ix order so it will match the arg order selected by create_query/union
    let downstream = world.view("upstream").find_all(UPSTREAM_UPSTREAM, view_id).iter().map(|upstream| {
        get_view_ix(world, &upstream[UPSTREAM_DOWNSTREAM])
    }).collect();
    Node{
        id: view_id.to_string(),
        view: view,
        upstream: upstream,
        downstream: downstream,
    }
}

fn create_flow(world: &World) -> Flow {
    let mut nodes = Vec::new();
    for schedule in world.view("schedule").iter() { // arrives in ix order
        let view_id = &schedule[SCHEDULE_VIEW];
        let view = world.view("view").find_one(VIEW_ID, view_id).clone();
        let view_kind = &view[VIEW_KIND];
        let node = create_node(world, view_id, view_kind);
        nodes.push(node);
    }
    Flow{
        nodes: nodes
    }
}

fn create_flow_state(world: &World, flow: &Flow) -> FlowState {
    let mut dirty = BitSet::new();
    let mut outputs = Vec::new();
    for (ix, node) in flow.nodes.iter().enumerate() {
        outputs.push(world.views.get(&node.id).map_or_else(
            || RefCell::new(Index::new()),
            |r| r.clone()
            ));
        match node.view {
            View::Input => (),
            _ => {dirty.insert(ix);},
        }
    }
    FlowState{
        dirty: dirty,
        outputs: outputs
    }
}

pub fn compile(world: &mut World) -> (Flow, FlowState) {
    for view_id in COMPILER_VIEWS.iter() {
        world.get_or_create(view_id);
    }
    create_upstream(world);
    create_schedule(world);
    let flow = create_flow(world);
    let flow_state = create_flow_state(world, &flow);
    (flow, flow_state)
}<|endoftext|>