<commit_before>use crate::core::compiler::CompileKind;
use crate::util::interning::InternedString;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use anyhow::bail;
use cargo_util::ProcessBuilder;
use serde::ser;
use std::cell::RefCell;
use std::path::PathBuf;

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The requested kind of compilation for this session
    pub requested_kinds: Vec<CompileKind>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// Do not abort the build as soon as there is an error.
    pub keep_going: bool,
    /// Build profile
    pub requested_profile: InternedString,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Output the unit graph to stdout instead of actually compiling.
    pub unit_graph: bool,
    /// An optional override of the rustc process for primary units
    pub primary_unit_rustc: Option<ProcessBuilder>,
    /// A thread used by `cargo fix` to receive messages on a socket regarding
    /// the success/failure of applying fixes.
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
    /// The directory to copy final artifacts to. Note that even if `out_dir` is
    /// set, a copy of artifacts still could be found a `target/(debug\release)`
    /// as usual.
    // Note that, although the cmd-line flag name is `out-dir`, in code we use
    // `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
    pub export_dir: Option<PathBuf>,
    /// `true` to output a future incompatibility report at the end of the build
    pub future_incompat_report: bool,
    /// Which kinds of build timings to output (empty if none).
    pub timing_outputs: Vec<TimingOutput>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<i32>,
        keep_going: bool,
        requested_targets: &[String],
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let cfg = config.build_config()?;
        let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?;
        if jobs == Some(0) {
            anyhow::bail!("jobs must not be zero")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let jobs = match jobs.or(cfg.jobs) {
            None => ::num_cpus::get() as u32,
            Some(0) => anyhow::bail!("jobs may not be 0"),
            Some(j) if j < 0 => (::num_cpus::get() as i32 + j).max(1) as u32,
            Some(j) => j as u32,
        };

        if config.cli_unstable().build_std.is_some() && requested_kinds[0].is_host() {
            // TODO: This should eventually be fixed.
            anyhow::bail!("-Zbuild-std requires --target");
        }

        Ok(BuildConfig {
            requested_kinds,
            jobs,
            keep_going,
            requested_profile: InternedString::new("dev"),
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            unit_graph: false,
            primary_unit_rustc: None,
            rustfix_diagnostic_server: RefCell::new(None),
            export_dir: None,
            future_incompat_report: false,
            timing_outputs: Vec::new(),
        })
    }

    /// Whether or not the *user* wants JSON output. Whether or not rustc
    /// actually uses JSON is decided in `add_error_format`.
    pub fn emit_json(&self) -> bool {
        matches!(self.message_format, MessageFormat::Json { .. })
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }

    pub fn single_requested_kind(&self) -> CargoResult<CompileKind> {
        match self.requested_kinds.len() {
            1 => Ok(self.requested_kinds[0]),
            _ => bail!("only one `--target` argument is supported"),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json {
        /// Whether rustc diagnostics are rendered by cargo or included into the
        /// output stream.
        render_diagnostics: bool,
        /// Whether the `rendered` field of rustc diagnostics are using the
        /// "short" rendering.
        short: bool,
        /// Whether the `rendered` field of rustc diagnostics embed ansi color
        /// codes.
        ansi: bool,
    },
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Unit`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// An example or library that will be scraped for function calls by `rustdoc`.
    Docscrape,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            Docscrape => "docscrape".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        matches!(self, CompileMode::Check { .. })
    }

    /// Returns `true` if this is generating documentation.
    pub fn is_doc(self) -> bool {
        matches!(self, CompileMode::Doc { .. })
    }

    /// Returns `true` if this a doc test.
    pub fn is_doc_test(self) -> bool {
        self == CompileMode::Doctest
    }

    /// Returns `true` if this is scraping examples for documentation.
    pub fn is_doc_scrape(self) -> bool {
        self == CompileMode::Docscrape
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        matches!(
            self,
            CompileMode::Test
                | CompileMode::Bench
                | CompileMode::Check { test: true }
                | CompileMode::Doctest
        )
    }

    /// Returns `true` if this is something that passes `--test` to rustc.
    pub fn is_rustc_test(self) -> bool {
        matches!(
            self,
            CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true }
        )
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }

    /// Returns `true` if this mode may generate an executable.
    ///
    /// Note that this also returns `true` for building libraries, so you also
    /// have to check the target.
    pub fn generates_executable(self) -> bool {
        matches!(
            self,
            CompileMode::Test | CompileMode::Bench | CompileMode::Build
        )
    }
}

/// Kinds of build timings we can output.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum TimingOutput {
    /// Human-readable HTML report
    Html,
    /// Machine-readable JSON (unstable)
    Json,
}
<commit_msg>make consistent error message<commit_after>use crate::core::compiler::CompileKind;
use crate::util::interning::InternedString;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use anyhow::bail;
use cargo_util::ProcessBuilder;
use serde::ser;
use std::cell::RefCell;
use std::path::PathBuf;

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The requested kind of compilation for this session
    pub requested_kinds: Vec<CompileKind>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// Do not abort the build as soon as there is an error.
    pub keep_going: bool,
    /// Build profile
    pub requested_profile: InternedString,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Output the unit graph to stdout instead of actually compiling.
    pub unit_graph: bool,
    /// An optional override of the rustc process for primary units
    pub primary_unit_rustc: Option<ProcessBuilder>,
    /// A thread used by `cargo fix` to receive messages on a socket regarding
    /// the success/failure of applying fixes.
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
    /// The directory to copy final artifacts to. Note that even if `out_dir` is
    /// set, a copy of artifacts still could be found a `target/(debug\release)`
    /// as usual.
    // Note that, although the cmd-line flag name is `out-dir`, in code we use
    // `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
    pub export_dir: Option<PathBuf>,
    /// `true` to output a future incompatibility report at the end of the build
    pub future_incompat_report: bool,
    /// Which kinds of build timings to output (empty if none).
    pub timing_outputs: Vec<TimingOutput>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<i32>,
        keep_going: bool,
        requested_targets: &[String],
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let cfg = config.build_config()?;
        let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?;
        if jobs == Some(0) {
            anyhow::bail!("jobs may not be 0")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let jobs = match jobs.or(cfg.jobs) {
            None => ::num_cpus::get() as u32,
            Some(0) => anyhow::bail!("jobs may not be 0"),
            Some(j) if j < 0 => (::num_cpus::get() as i32 + j).max(1) as u32,
            Some(j) => j as u32,
        };

        if config.cli_unstable().build_std.is_some() && requested_kinds[0].is_host() {
            // TODO: This should eventually be fixed.
            anyhow::bail!("-Zbuild-std requires --target");
        }

        Ok(BuildConfig {
            requested_kinds,
            jobs,
            keep_going,
            requested_profile: InternedString::new("dev"),
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            unit_graph: false,
            primary_unit_rustc: None,
            rustfix_diagnostic_server: RefCell::new(None),
            export_dir: None,
            future_incompat_report: false,
            timing_outputs: Vec::new(),
        })
    }

    /// Whether or not the *user* wants JSON output. Whether or not rustc
    /// actually uses JSON is decided in `add_error_format`.
    pub fn emit_json(&self) -> bool {
        matches!(self.message_format, MessageFormat::Json { .. })
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }

    pub fn single_requested_kind(&self) -> CargoResult<CompileKind> {
        match self.requested_kinds.len() {
            1 => Ok(self.requested_kinds[0]),
            _ => bail!("only one `--target` argument is supported"),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json {
        /// Whether rustc diagnostics are rendered by cargo or included into the
        /// output stream.
        render_diagnostics: bool,
        /// Whether the `rendered` field of rustc diagnostics are using the
        /// "short" rendering.
        short: bool,
        /// Whether the `rendered` field of rustc diagnostics embed ansi color
        /// codes.
        ansi: bool,
    },
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Unit`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// An example or library that will be scraped for function calls by `rustdoc`.
    Docscrape,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            Docscrape => "docscrape".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        matches!(self, CompileMode::Check { .. })
    }

    /// Returns `true` if this is generating documentation.
    pub fn is_doc(self) -> bool {
        matches!(self, CompileMode::Doc { .. })
    }

    /// Returns `true` if this a doc test.
    pub fn is_doc_test(self) -> bool {
        self == CompileMode::Doctest
    }

    /// Returns `true` if this is scraping examples for documentation.
    pub fn is_doc_scrape(self) -> bool {
        self == CompileMode::Docscrape
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        matches!(
            self,
            CompileMode::Test
                | CompileMode::Bench
                | CompileMode::Check { test: true }
                | CompileMode::Doctest
        )
    }

    /// Returns `true` if this is something that passes `--test` to rustc.
    pub fn is_rustc_test(self) -> bool {
        matches!(
            self,
            CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true }
        )
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }

    /// Returns `true` if this mode may generate an executable.
    ///
    /// Note that this also returns `true` for building libraries, so you also
    /// have to check the target.
    pub fn generates_executable(self) -> bool {
        matches!(
            self,
            CompileMode::Test | CompileMode::Bench | CompileMode::Build
        )
    }
}

/// Kinds of build timings we can output.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum TimingOutput {
    /// Human-readable HTML report
    Html,
    /// Machine-readable JSON (unstable)
    Json,
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::fmt;

use cells::Cell;
use grid_traits::{GridDimensions, GridIterators};

pub struct RectGridIterators<'a> {
    cell_iter_dimension: PhantomData<&'a GridDimensions>
}
impl<'a, CellT: Cell> GridIterators<CellT> for RectGridIterators<'a> {
    type CellIter = RectGridCellIter<'a, CellT>;
    type BatchIter = RectBatchIter;

    fn iter(&self, dimensions: &'a GridDimensions) -> Self::CellIter {
        RectGridCellIter::<CellT> {
            dimensions: dimensions,
            current_cell_number: 0,
            cells_count: dimensions.size().0,
            cell_type: PhantomData
        }
    }

    fn iter_row(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter {}
    }

    fn iter_column(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter {}
    }
}

#[derive(Copy, Clone)]
pub struct RectGridCellIter<'a, CellT: Cell> {
    dimensions: &'a GridDimensions,
    current_cell_number: usize,
    cells_count: usize,
    cell_type: PhantomData<CellT>
}
impl<'a, CellT: Cell> fmt::Debug for RectGridCellIter<'a, CellT> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CellIter :: current_cell_number: {:?}, cells_count: {:?}",
               self.current_cell_number, self.cells_count)
    }
}
impl<'a, CellT: Cell> ExactSizeIterator for RectGridCellIter<'a, CellT> { } // default impl using size_hint()
impl<'a, CellT: Cell> Iterator for RectGridCellIter<'a, CellT> {
    type Item = CellT::Coord;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current_cell_number < self.cells_count {
            let coord = Self::Item::from_row_major_index(self.current_cell_number,
                                                         self.dimensions);
            self.current_cell_number += 1;
            Some(coord)
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower_bound = self.cells_count - self.current_cell_number;
        let upper_bound = lower_bound;
        (lower_bound, Some(upper_bound))
    }
}

struct RectBatchIter {

}
<commit_msg>iterators wip<commit_after>use std::marker::PhantomData;
use std::fmt;

use cells::Cell;
use grid_traits::{GridDimensions, GridIterators};
use units::{RowsCount, RowLength, RowIndex, ColumnsCount, ColumnLength,
            ColumnIndex, NodesCount, EdgesCount};

pub struct RectGridIterators<'a> {
    cell_iter_dimension: PhantomData<&'a GridDimensions>
}
impl<'a, CellT: Cell> GridIterators<CellT> for RectGridIterators<'a> {
    type CellIter = RectGridCellIter<'a, CellT>;
    type BatchIter = RectBatchIter<CellT>;

    fn iter(&self, dimensions: &'a GridDimensions) -> Self::CellIter {
        RectGridCellIter::<CellT> {
            dimensions: dimensions,
            current_cell_number: 0,
            cells_count: dimensions.size().0,
            cell_type: PhantomData
        }
    }

    fn iter_row(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter::<CellT>::new(BatchIterType::Row, dimensions)
    }

    fn iter_column(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter::<CellT>::new(BatchIterType::Column, dimensions)
    }
}

#[derive(Copy, Clone)]
pub struct RectGridCellIter<'a, CellT: Cell> {
    dimensions: &'a GridDimensions,
    current_cell_number: usize,
    cells_count: usize,
    cell_type: PhantomData<CellT>
}

impl<'a, CellT: Cell> fmt::Debug for RectGridCellIter<'a, CellT> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CellIter :: current_cell_number: {:?}, cells_count: {:?}",
               self.current_cell_number, self.cells_count)
    }
}

impl<'a, CellT: Cell> ExactSizeIterator for RectGridCellIter<'a, CellT> { } // default impl using size_hint()
impl<'a, CellT: Cell> Iterator for RectGridCellIter<'a, CellT> {
    type Item = CellT::Coord;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current_cell_number < self.cells_count {
            let coord = Self::Item::from_row_major_index(self.current_cell_number,
                                                         self.dimensions);
            self.current_cell_number += 1;
            Some(coord)
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower_bound = self.cells_count - self.current_cell_number;
        let upper_bound = lower_bound;
        (lower_bound, Some(upper_bound))
    }
}

#[derive(Debug, Copy, Clone)]
enum BatchIterType {
    Row,
    Column,
}

pub struct RectBatchIter<CellT> {
    iter_type: BatchIterType,
    iter_initial_length: usize,
    current_index: usize,
    row_length: RowLength,
    rows_size: RowsCount,
    col_length: ColumnLength,
    cols_size: ColumnsCount,
    cell_type: PhantomData<CellT>,
}

impl<CellT> RectBatchIter<CellT> {
    fn new(iter_type: BatchIterType, dimensions: &GridDimensions) -> RectBatchIter<CellT> {
        let rows_size = dimensions.rows();
        let cols_size = dimensions.columns();
        RectBatchIter {
            iter_type: BatchIterType::Row,
            iter_initial_length: rows_size * cols_size,
            current_index: 0,
            row_length: dimensions.row_length(None).unwrap(),
            rows_size: rows_size,
            col_length: dimensions.column_length(None),
            cols_size: cols_size,
        }
    }
}

impl<CellT: Cell> ExactSizeIterator for RectBatchIter<CellT> { } // default impl using size_hint()
impl<CellT: Cell> Iterator for RectBatchIter<CellT> {
    type Item = Vec<CellT::Coord>;
    fn next(&mut self) -> Option<Self::Item> {

        if let BatchIterType::Row = self.iter_type {

            let RowsCount(count) = self.rows_size;
            if self.current_index < count {
                let RowLength(length) = self.row_length;
                let coords = (0..length)
                    .into_iter()
                    .map(|i: usize| {
                        CellT::Coord::from_row_column_indices(ColumnIndex(i), RowIndex(self.current_index))
                    })
                    .collect();
                self.current_index += 1;
                Some(coords)
            } else {
                None
            }

        } else {

            let ColumnsCount(count) = self.cols_size;
            if self.current_index < count {
                let ColumnLength(length) = self.col_length;
                let coords = (0..length)
                    .into_iter()
                    .map(|i: usize| {
                        CellT::Coord::from_row_column_indices(ColumnIndex(self.current_index), RowIndex(i))
                    })
                    .collect();
                self.current_index += 1;
                Some(coords)
            } else {
                None
            }

        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower_bound = self.iter_initial_length - self.current_index;
        let upper_bound = lower_bound;
        (lower_bound, Some(upper_bound))
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use error::KarmaError;
use chrono::{DateTime, Local};
use dazeus::{DaZeusClient, Scope, Response};
use std::ascii::AsciiExt;

pub const STORE_PREFIX: &'static str = "dazeus_karma.";

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct KarmaChange {
    pub up: u64,
    pub down: u64
}

impl KarmaChange {
    pub fn new(up: u64, down: u64) -> KarmaChange {
        KarmaChange { up: up, down: down }
    }

    pub fn total(&self) -> i64 {
        (self.up as i64) - (self.down as i64)
    }

    pub fn to_string(&self) -> String {
        format!("{} (+{}, -{})", self.total(), self.up, self.down)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum KarmaStyle {
    Notify,
    Silent,
    Implicit
}

impl KarmaStyle {
    pub fn most_explicit(first: KarmaStyle, second: KarmaStyle) -> KarmaStyle {
        if first == KarmaStyle::Implicit && second == KarmaStyle::Implicit {
            KarmaStyle::Implicit
        } else if first == KarmaStyle::Silent && second != KarmaStyle::Notify {
            KarmaStyle::Silent
        } else if first == KarmaStyle::Notify {
            KarmaStyle::Notify
        } else {
            second
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Karma {
    pub term: String,
    pub change: KarmaChange,
    pub style: KarmaStyle
}

#[derive(Debug, Clone, PartialEq)]
pub struct KarmaValue {
    pub term: String,
    pub original_term: String,
    pub votes: KarmaChange,
    pub last_vote: DateTime<Local>,
    pub first_vote: DateTime<Local>
}

impl KarmaValue {
    pub fn new(term: &str) -> KarmaValue {
        KarmaValue {
            term: term.to_ascii_lowercase(),
            original_term: term.to_string(),
            votes: KarmaChange::new(0, 0),
            last_vote: Local::now(),
            first_vote: Local::now()
        }
    }

    pub fn vote(&mut self, karma: &Karma) {
        self.last_vote = Local::now();
        self.votes.up += karma.change.up;
        self.votes.down += karma.change.down;
    }

    pub fn from_json(data: json::Json) -> Result<KarmaValue, Box<::std::error::Error>> {
        macro_rules! get_key {
            ($o:expr, $s:expr, $i_is:ident, $i_as:ident) => (match $o.get($s) {
                Some(m) if m.$i_is() => m.$i_as().unwrap(),
                _ => return Err(From::from(KarmaError::new(&format!("No value or invalid value for key '{}'", $s)[..])))
            });
        }

        if data.is_object() {
            let obj = data.as_object().unwrap();
            let term = get_key!(obj, "term", is_string, as_string);
            let first_vote_str = get_key!(obj, "first_vote", is_string, as_string);
            let last_vote_str = get_key!(obj, "last_vote", is_string, as_string);
            let votes = get_key!(obj, "votes", is_object, as_object);
            let upvotes = get_key!(votes, "up", is_u64, as_u64);
            let downvotes = get_key!(votes, "down", is_u64, as_u64);

            let first_vote = try!(first_vote_str.parse::<DateTime<Local>>());
            let last_vote = try!(last_vote_str.parse::<DateTime<Local>>());

            Ok(KarmaValue {
                term: term.to_ascii_lowercase(),
                original_term: term.to_string(),
                votes: KarmaChange::new(upvotes, downvotes),
                last_vote: last_vote,
                first_vote: first_vote
            })
        } else {
            Err(From::from(KarmaError::new("Invalid json: not an object")))
        }
    }

    pub fn from_str(s: &str) -> Result<KarmaValue, Box<::std::error::Error>> {
        let data = try!(json::Json::from_str(s));
        let karma = KarmaValue::from_json(data);
        match karma {
            Ok(mut k) => {
                k.original_term = k.term.clone();
                Ok(k)
            },
            o => o
        }
    }

    pub fn from_response(r: &Response) -> Result<KarmaValue, Box<::std::error::Error>> {
        match r.get_str("value") {
            Some(s) => KarmaValue::from_str(s),
            None => Err(From::from(KarmaError::new("No value found in response"))),
        }
    }

    pub fn from_dazeus(dazeus: &DaZeusClient, scope: Scope, term: &str) -> Result<KarmaValue, Box<::std::error::Error>> {
        let property = format!("{}{}", STORE_PREFIX, term);
        let mut karma = KarmaValue::from_response(&dazeus.get_property(&property[..].to_ascii_lowercase(), scope));
        if let Ok(ref mut k) = karma {
            k.original_term = term.to_string();
        }
        karma
    }

    pub fn to_string(&self) -> String {
        match self.votes.total() {
            0 => format!("{} has neutral karma (+{}, -{})", self.original_term, self.votes.up, self.votes.down),
            _ => format!("{} has a karma of {}", self.original_term, self.votes.to_string()),
        }
    }
}

impl json::ToJson for KarmaValue {
    fn to_json(&self) -> json::Json {
        let mut obj = json::Object::new();
        obj.insert("term".to_string(), self.term.to_json());

        let mut votes = json::Object::new();
        votes.insert("up".to_string(), self.votes.up.to_json());
        votes.insert("down".to_string(), self.votes.down.to_json());

        obj.insert("votes".to_string(), votes.to_json());
        obj.insert("first_vote".to_string(), self.first_vote.format("%FT%TZ").to_string().to_json());
        obj.insert("last_vote".to_string(), self.last_vote.format("%FT%TZ").to_string().to_json());

        obj.to_json()
    }
}
<commit_msg>Allow up and down to be strings and convert them to u64<commit_after>use rustc_serialize::json;
use error::KarmaError;
use chrono::{DateTime, Local};
use dazeus::{DaZeusClient, Scope, Response};
use std::ascii::AsciiExt;

pub const STORE_PREFIX: &'static str = "dazeus_karma.";

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct KarmaChange {
    pub up: u64,
    pub down: u64
}

impl KarmaChange {
    pub fn new(up: u64, down: u64) -> KarmaChange {
        KarmaChange { up: up, down: down }
    }

    pub fn total(&self) -> i64 {
        (self.up as i64) - (self.down as i64)
    }

    pub fn to_string(&self) -> String {
        format!("{} (+{}, -{})", self.total(), self.up, self.down)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum KarmaStyle {
    Notify,
    Silent,
    Implicit
}

impl KarmaStyle {
    pub fn most_explicit(first: KarmaStyle, second: KarmaStyle) -> KarmaStyle {
        if first == KarmaStyle::Implicit && second == KarmaStyle::Implicit {
            KarmaStyle::Implicit
        } else if first == KarmaStyle::Silent && second != KarmaStyle::Notify {
            KarmaStyle::Silent
        } else if first == KarmaStyle::Notify {
            KarmaStyle::Notify
        } else {
            second
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Karma {
    pub term: String,
    pub change: KarmaChange,
    pub style: KarmaStyle
}

#[derive(Debug, Clone, PartialEq)]
pub struct KarmaValue {
    pub term: String,
    pub original_term: String,
    pub votes: KarmaChange,
    pub last_vote: DateTime<Local>,
    pub first_vote: DateTime<Local>
}

impl KarmaValue {
    pub fn new(term: &str) -> KarmaValue {
        KarmaValue {
            term: term.to_ascii_lowercase(),
            original_term: term.to_string(),
            votes: KarmaChange::new(0, 0),
            last_vote: Local::now(),
            first_vote: Local::now()
        }
    }

    pub fn vote(&mut self, karma: &Karma) {
        self.last_vote = Local::now();
        self.votes.up += karma.change.up;
        self.votes.down += karma.change.down;
    }

    pub fn from_json(data: json::Json) -> Result<KarmaValue, Box<::std::error::Error>> {
        macro_rules! get_key {
            ($o:expr, $s:expr, $i_is:ident, $i_as:ident) => (match $o.get($s) {
                Some(m) if m.$i_is() => m.$i_as().unwrap(),
                _ => return Err(From::from(KarmaError::new(&format!("No value or invalid value for key '{}'", $s)[..])))
            });
        }

        if data.is_object() {
            let obj = data.as_object().unwrap();
            let term = get_key!(obj, "term", is_string, as_string);
            let first_vote_str = get_key!(obj, "first_vote", is_string, as_string);
            let last_vote_str = get_key!(obj, "last_vote", is_string, as_string);
            let votes = get_key!(obj, "votes", is_object, as_object);

            let upvotes = match votes.get("up") {
                Some(m) if m.is_u64() => m.as_u64().unwrap(),
                Some(m) if m.is_string() && m.as_string().unwrap().parse::<u64>().is_ok() => m.as_string().unwrap().parse().unwrap(),
                _ => return Err(From::from(KarmaError::new("No value or invalid value for key 'up'")))
            };

            let downvotes = match votes.get("down") {
                Some(m) if m.is_u64() => m.as_u64().unwrap(),
                Some(m) if m.is_string() && m.as_string().unwrap().parse::<u64>().is_ok() => m.as_string().unwrap().parse().unwrap(),
                _ => return Err(From::from(KarmaError::new("No value or invalid value for key 'down'")))
            };

            let first_vote = try!(first_vote_str.parse::<DateTime<Local>>());
            let last_vote = try!(last_vote_str.parse::<DateTime<Local>>());

            Ok(KarmaValue {
                term: term.to_ascii_lowercase(),
                original_term: term.to_string(),
                votes: KarmaChange::new(upvotes, downvotes),
                last_vote: last_vote,
                first_vote: first_vote
            })
        } else {
            Err(From::from(KarmaError::new("Invalid json: not an object")))
        }
    }

    pub fn from_str(s: &str) -> Result<KarmaValue, Box<::std::error::Error>> {
        let data = try!(json::Json::from_str(s));
        let karma = KarmaValue::from_json(data);
        match karma {
            Ok(mut k) => {
                k.original_term = k.term.clone();
                Ok(k)
            },
            o => o
        }
    }

    pub fn from_response(r: &Response) -> Result<KarmaValue, Box<::std::error::Error>> {
        match r.get_str("value") {
            Some(s) => KarmaValue::from_str(s),
            None => Err(From::from(KarmaError::new("No value found in response"))),
        }
    }

    pub fn from_dazeus(dazeus: &DaZeusClient, scope: Scope, term: &str) -> Result<KarmaValue, Box<::std::error::Error>> {
        let property = format!("{}{}", STORE_PREFIX, term);
        let mut karma = KarmaValue::from_response(&dazeus.get_property(&property[..].to_ascii_lowercase(), scope));
        if let Ok(ref mut k) = karma {
            k.original_term = term.to_string();
        }
        karma
    }

    pub fn to_string(&self) -> String {
        match self.votes.total() {
            0 => format!("{} has neutral karma (+{}, -{})", self.original_term, self.votes.up, self.votes.down),
            _ => format!("{} has a karma of {}", self.original_term, self.votes.to_string()),
        }
    }
}

impl json::ToJson for KarmaValue {
    fn to_json(&self) -> json::Json {
        let mut obj = json::Object::new();
        obj.insert("term".to_string(), self.term.to_json());

        let mut votes = json::Object::new();
        votes.insert("up".to_string(), self.votes.up.to_json());
        votes.insert("down".to_string(), self.votes.down.to_json());

        obj.insert("votes".to_string(), votes.to_json());
        obj.insert("first_vote".to_string(), self.first_vote.format("%FT%TZ").to_string().to_json());
        obj.insert("last_vote".to_string(), self.last_vote.format("%FT%TZ").to_string().to_json());

        obj.to_json()
    }
}
<|endoftext|>


<commit_before>#![feature(try_trait_v2)]

mod builtin_functions;
mod compiler;
mod database;
mod discover;
mod incremental;
mod input;
mod language_server;

use crate::compiler::ast_to_hir::AstToHir;
use crate::compiler::cst_to_ast::CstToAst;
use crate::compiler::string_to_cst::StringToCst;
use crate::database::PROJECT_DIRECTORY;
use crate::{database::Database, input::Input};
use language_server::CandyLanguageServer;
use log;
use lspower::{LspService, Server};
use std::env::current_dir;
use std::path::PathBuf;
use structopt::StructOpt;

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

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

    #[structopt(long)]
    print_ast: bool,

    #[structopt(long)]
    print_hir: bool,

    #[structopt(long)]
    no_run: bool,

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

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

fn run(options: CandyRunOptions) {
    *PROJECT_DIRECTORY.lock().unwrap() = Some(current_dir().unwrap());

    log::debug!("Running `{}`.\n", options.file.display());

    let input: Input = options.file.clone().into();
    let db = Database::default();

    log::info!("Parsing string to CST…");
    let (cst, errors) = db
        .cst_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_cst {
        log::info!("CST: {:#?}", cst);
    }
    if !errors.is_empty() {
        log::error!(
            "Errors occurred while parsing string to CST…:\n{:#?}",
            errors
        );
        return;
    }

    log::info!("Lowering CST to AST…");
    let (asts, _, errors) = db
        .ast_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_ast {
        log::info!("AST: {:#?}", asts);
    }
    if !errors.is_empty() {
        log::error!("Errors occurred while lowering CST to AST:\n{:#?}", errors);
        return;
    }

    log::info!("Compiling AST to HIR…");
    let (hir, _, errors) = db
        .hir_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_hir {
        log::info!("HIR: {:?}", hir);
    }
    if !errors.is_empty() {
        log::error!("Errors occurred while lowering AST to HIR:\n{:#?}", errors);
        return;
    }

    // let reports = analyze((*lambda).clone());
    // for report in reports {
    //     log::error!("Report: {:?}", report);
    // }

    // if !options.no_run {
    //     log::info!("Executing code…");
    //     let mut fiber = fiber::Fiber::new(hir.as_ref().clone());
    //     fiber.run();
    //     match fiber.status() {
    //         FiberStatus::Running => log::info!("Fiber is still running."),
    //         FiberStatus::Done(value) => log::info!("Fiber is done: {:#?}", value),
    //         FiberStatus::Panicked(value) => log::error!("Fiber panicked: {:#?}", value),
    //     }
    // }
}

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

fn init_logger() {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{} [{:>5}] {} {}",
                chrono::Local::now().format("%H:%M:%S"),
                record.level(),
                record.target(),
                message
            ))
        })
        .level_for("salsa", log::LevelFilter::Error)
        .level_for("tokio_util", log::LevelFilter::Error)
        .level_for("lspower::transport", log::LevelFilter::Error)
        .chain(std::io::stderr())
        .apply()
        .unwrap();
}
<commit_msg>feat(compiler): add --print-ast-cst-id-map CLI flag<commit_after>#![feature(try_trait_v2)]

mod builtin_functions;
mod compiler;
mod database;
mod discover;
mod incremental;
mod input;
mod language_server;

use crate::compiler::ast_to_hir::AstToHir;
use crate::compiler::cst_to_ast::CstToAst;
use crate::compiler::string_to_cst::StringToCst;
use crate::database::PROJECT_DIRECTORY;
use crate::{database::Database, input::Input};
use itertools::Itertools;
use language_server::CandyLanguageServer;
use log;
use lspower::{LspService, Server};
use std::env::current_dir;
use std::path::PathBuf;
use structopt::StructOpt;

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

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

    #[structopt(long)]
    print_ast: bool,
    #[structopt(long)]
    print_ast_cst_id_map: bool,

    #[structopt(long)]
    print_hir: bool,

    #[structopt(long)]
    no_run: bool,

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

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

fn run(options: CandyRunOptions) {
    *PROJECT_DIRECTORY.lock().unwrap() = Some(current_dir().unwrap());

    log::debug!("Running `{}`.\n", options.file.display());

    let input: Input = options.file.clone().into();
    let db = Database::default();

    log::info!("Parsing string to CST…");
    let (cst, errors) = db
        .cst_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_cst {
        log::info!("CST: {:#?}", cst);
    }
    if !errors.is_empty() {
        log::error!(
            "Errors occurred while parsing string to CST…:\n{:#?}",
            errors
        );
        return;
    }

    log::info!("Lowering CST to AST…");
    let (asts, ast_cst_id_map, errors) = db
        .ast_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_ast {
        log::info!("AST: {:#?}", asts);
    }
    if options.print_ast_cst_id_map {
        log::info!(
            "AST → CST Id map: {}",
            ast_cst_id_map
                .keys()
                .into_iter()
                .sorted_by_key(|it| it.local)
                .map(|key| format!("{}: {}", key.local, ast_cst_id_map[key].0))
                .join(", ")
        );
    }
    if !errors.is_empty() {
        log::error!("Errors occurred while lowering CST to AST:\n{:#?}", errors);
        return;
    }

    log::info!("Compiling AST to HIR…");
    let (hir, _, errors) = db
        .hir_raw(input.clone())
        .unwrap_or_else(|| panic!("File `{}` not found.", options.file.display()));
    if options.print_hir {
        log::info!("HIR: {:?}", hir);
    }
    if !errors.is_empty() {
        log::error!("Errors occurred while lowering AST to HIR:\n{:#?}", errors);
        return;
    }

    // let reports = analyze((*lambda).clone());
    // for report in reports {
    //     log::error!("Report: {:?}", report);
    // }

    // if !options.no_run {
    //     log::info!("Executing code…");
    //     let mut fiber = fiber::Fiber::new(hir.as_ref().clone());
    //     fiber.run();
    //     match fiber.status() {
    //         FiberStatus::Running => log::info!("Fiber is still running."),
    //         FiberStatus::Done(value) => log::info!("Fiber is done: {:#?}", value),
    //         FiberStatus::Panicked(value) => log::error!("Fiber panicked: {:#?}", value),
    //     }
    // }
}

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

fn init_logger() {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{} [{:>5}] {} {}",
                chrono::Local::now().format("%H:%M:%S"),
                record.level(),
                record.target(),
                message
            ))
        })
        .level_for("salsa", log::LevelFilter::Error)
        .level_for("tokio_util", log::LevelFilter::Error)
        .level_for("lspower::transport", log::LevelFilter::Error)
        .chain(std::io::stderr())
        .apply()
        .unwrap();
}
<|endoftext|>


<commit_before>//! Building blocks for meta rules.

pub use self::lines::Lines;
pub use self::node::Node;
pub use self::number::Number;
pub use self::optional::Optional;
pub use self::repeat::Repeat;
pub use self::rule::Rule;
pub use self::select::Select;
pub use self::separated_by::SeparatedBy;
pub use self::sequence::Sequence;
pub use self::text::Text;
pub use self::token::Token;
pub use self::until_any::UntilAny;
pub use self::until_any_or_whitespace::UntilAnyOrWhitespace;
pub use self::whitespace::Whitespace;

use std::rc::Rc;
use range::Range;
use {
    MetaData,
    ParseError,
    Tokenizer,
    TokenizerState,
};

mod lines;
mod node;
mod number;
mod optional;
mod repeat;
mod rule;
mod select;
mod separated_by;
mod sequence;
mod text;
mod token;
mod until_any;
mod until_any_or_whitespace;
mod whitespace;

/// Parses text with rules.
pub fn parse(
    rules: &[(Rc<String>, Rule)],
    text: &str
) -> Result<Vec<(Range, MetaData)>, (Range, ParseError)> {
    let chars: Vec<char> = text.chars().collect();
    let mut tokenizer = Tokenizer::new();
    let s = TokenizerState::new();
    let n = match rules.len() {
        0 => { return Err((Range::empty(0), ParseError::NoRules)); }
        x => x
    };
    let res = rules[n - 1].1.parse(&mut tokenizer, &s, &chars, 0, rules);
    match res {
        Ok((range, s, opt_error)) => {
            // Report error if did not reach the end of text.
            if range.next_offset() < text.len() {
                Err(ret_err(
                    (Range::empty(range.next_offset()),
                        ParseError::ExpectedEnd),
                    opt_error
                ))
            } else {
                tokenizer.tokens.truncate(s.0);
                Ok(tokenizer.tokens)
            }
        }
        Err((err_range, err)) => {
            Err((err_range, err))
        }
    }
}

/// Updates the references such that they point to each other.
pub fn update_refs(rules: &[(Rc<String>, Rule)]) {
    for r in rules {
        r.1.update_refs(rules);
    }
}

/// A parse result succeeds with a new state,
/// plus an optional error to replace other errors if it is deeper.
/// The deepest error is likely the most useful.
pub type ParseResult<S> = Result<(Range, S, Option<(Range, ParseError)>),
    (Range, ParseError)>;

/// Updates the parser state.
/// Used by rules that have multiple sub rules.
#[inline(always)]
fn update<'a>(
    range: Range,
    err: Option<(Range, ParseError)>,
    chars: &mut &'a [char],
    offset: &mut usize,
    opt_error: &mut Option<(Range, ParseError)>
) {
    let next_offset = range.next_offset();
    *chars = &chars[next_offset - *offset..];
    *offset = next_offset;
    err_update(err, opt_error);
}

/// Picks deepest error, overwriting with the newest one if they are
/// equally deep.
#[inline(always)]
fn err_update(
    err: Option<(Range, ParseError)>,
    opt_error: &mut Option<(Range, ParseError)>
) {
    if let &mut Some(ref mut opt_error) = opt_error {
        if let Some(err) = err {
            if opt_error.0.next_offset() <= err.0.next_offset() {
                *opt_error = err;
            }
        }
    } else {
        *opt_error = err;
    };
}

/// This is used to pick the deepest error or two alternatives,
/// one from a rule that fails certainly and another that could be optional.
#[inline(always)]
fn ret_err(a: (Range, ParseError), b: Option<(Range, ParseError)>) ->
    (Range, ParseError) {
    if let Some(b) = b {
        if b.0.next_offset() > a.0.next_offset() {
            b
        } else {
            a
        }
    } else {
        a
    }
}

#[cfg(test)]
mod tests{
    use range::Range;
    use super::*;

    #[test]
    fn no_rules() {
        assert_eq!(parse(&[], ""),
            Err((Range::empty(0), ParseError::NoRules)));
    }
}
<commit_msg>Fixed unit test<commit_after>//! Building blocks for meta rules.

pub use self::lines::Lines;
pub use self::node::Node;
pub use self::number::Number;
pub use self::optional::Optional;
pub use self::repeat::Repeat;
pub use self::rule::Rule;
pub use self::select::Select;
pub use self::separated_by::SeparatedBy;
pub use self::sequence::Sequence;
pub use self::text::Text;
pub use self::token::Token;
pub use self::until_any::UntilAny;
pub use self::until_any_or_whitespace::UntilAnyOrWhitespace;
pub use self::whitespace::Whitespace;

use std::rc::Rc;
use range::Range;
use {
    MetaData,
    ParseError,
    Tokenizer,
    TokenizerState,
};

mod lines;
mod node;
mod number;
mod optional;
mod repeat;
mod rule;
mod select;
mod separated_by;
mod sequence;
mod text;
mod token;
mod until_any;
mod until_any_or_whitespace;
mod whitespace;

/// Parses text with rules.
pub fn parse(
    rules: &[(Rc<String>, Rule)],
    text: &str
) -> Result<Vec<(Range, MetaData)>, (Range, ParseError)> {
    let chars: Vec<char> = text.chars().collect();
    let mut tokenizer = Tokenizer::new();
    let s = TokenizerState::new();
    let n = match rules.len() {
        0 => { return Err((Range::empty(0), ParseError::NoRules)); }
        x => x
    };
    let res = rules[n - 1].1.parse(&mut tokenizer, &s, &chars, 0, rules);
    match res {
        Ok((range, s, opt_error)) => {
            // Report error if did not reach the end of text.
            if range.next_offset() < text.len() {
                Err(ret_err(
                    (Range::empty(range.next_offset()),
                        ParseError::ExpectedEnd),
                    opt_error
                ))
            } else {
                tokenizer.tokens.truncate(s.0);
                Ok(tokenizer.tokens)
            }
        }
        Err((err_range, err)) => {
            Err((err_range, err))
        }
    }
}

/// Updates the references such that they point to each other.
pub fn update_refs(rules: &[(Rc<String>, Rule)]) {
    for r in rules {
        r.1.update_refs(rules);
    }
}

/// A parse result succeeds with a new state,
/// plus an optional error to replace other errors if it is deeper.
/// The deepest error is likely the most useful.
pub type ParseResult<S> = Result<(Range, S, Option<(Range, ParseError)>),
    (Range, ParseError)>;

/// Updates the parser state.
/// Used by rules that have multiple sub rules.
#[inline(always)]
fn update<'a>(
    range: Range,
    err: Option<(Range, ParseError)>,
    chars: &mut &'a [char],
    offset: &mut usize,
    opt_error: &mut Option<(Range, ParseError)>
) {
    let next_offset = range.next_offset();
    *chars = &chars[next_offset - *offset..];
    *offset = next_offset;
    err_update(err, opt_error);
}

/// Picks deepest error, overwriting with the newest one if they are
/// equally deep.
#[inline(always)]
fn err_update(
    err: Option<(Range, ParseError)>,
    opt_error: &mut Option<(Range, ParseError)>
) {
    if let &mut Some(ref mut opt_error) = opt_error {
        if let Some(err) = err {
            if opt_error.0.next_offset() <= err.0.next_offset() {
                *opt_error = err;
            }
        }
    } else {
        *opt_error = err;
    };
}

/// This is used to pick the deepest error or two alternatives,
/// one from a rule that fails certainly and another that could be optional.
#[inline(always)]
fn ret_err(a: (Range, ParseError), b: Option<(Range, ParseError)>) ->
    (Range, ParseError) {
    if let Some(b) = b {
        if b.0.next_offset() > a.0.next_offset() {
            b
        } else {
            a
        }
    } else {
        a
    }
}

#[cfg(test)]
mod tests{
    use range::Range;
    use all::*;

    #[test]
    fn no_rules() {
        assert_eq!(parse(&[], ""),
            Err((Range::empty(0), ParseError::NoRules)));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

#[derive(Debug)]
pub struct Block {
  pub is_last: bool,
  pub length: u32,
  pub data: BlockData,
}

#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  StreamInfo(StreamInfo),
  Padding(u32),
  Application(Application),
  SeekTable(Vec<SeekPoint>),
  VorbisComment(VorbisComment),
  CueSheet(CueSheet),
  Picture(Picture),
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: Vec<u8>,
}

/// Data used by third-party applications
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  pub id: String,
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  pub vendor_string: String,
  pub comments: HashMap<String, String>,
}

/// Stores cue information
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  pub media_catalog_number: String,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  pub offset: u64,
  pub number: u8,
  pub isrc: String,
  pub is_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

/// Stores pictures associated with a FLAC file
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  pub picture_type: PictureType,
  pub mime_type: String,
  pub description: String,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogo,
  PublisherLogo,
}

enum ParserState {
  FLAC,
  Header,
  MetaData,
}

pub struct MetaDataConsumer {
  state: ParserState,
  is_last: bool,
  block_type: u8,
  length: u32,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::FLAC,
      is_last: false,
      block_type: 127,
      length: 0,
      data: Vec::new(),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::FLAC     => {
        match tag!(input, "fLaC") {
          IResult::Done(_, _) => {
            self.state = ParserState::Header;
            ConsumerState::Await(4, 4)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      }
      ParserState::Header   => {
        match header(input) {
          IResult::Done(_, data) => {
            let (is_last, block_type, length) = data;

            self.state      = ParserState::MetaData;
            self.is_last    = is_last;
            self.block_type = block_type;
            self.length     = length;

            ConsumerState::Await(4, length as usize)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      },
      ParserState::MetaData => {
        let length = self.length as usize;

        match block_data(input, self.block_type, self.length) {
          IResult::Done(_, data) => {
            self.data.push(Block {
              is_last: self.is_last,
              length: self.length,
              data: data,
            });

            if self.is_last {
              ConsumerState::ConsumerDone
            } else {
              self.state = ParserState::Header;

              ConsumerState::Await(length, 4)
            }
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, length),
        }
      }
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<commit_msg>Change md5 to fixed size<commit_after>use std::collections::HashMap;
use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

#[derive(Debug)]
pub struct Block {
  pub is_last: bool,
  pub length: u32,
  pub data: BlockData,
}

#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  StreamInfo(StreamInfo),
  Padding(u32),
  Application(Application),
  SeekTable(Vec<SeekPoint>),
  VorbisComment(VorbisComment),
  CueSheet(CueSheet),
  Picture(Picture),
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: [u8; 16],
}

/// Data used by third-party applications
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  pub id: String,
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  pub vendor_string: String,
  pub comments: HashMap<String, String>,
}

/// Stores cue information
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  pub media_catalog_number: String,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  pub offset: u64,
  pub number: u8,
  pub isrc: String,
  pub is_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

/// Stores pictures associated with a FLAC file
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  pub picture_type: PictureType,
  pub mime_type: String,
  pub description: String,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogo,
  PublisherLogo,
}

enum ParserState {
  FLAC,
  Header,
  MetaData,
}

pub struct MetaDataConsumer {
  state: ParserState,
  is_last: bool,
  block_type: u8,
  length: u32,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::FLAC,
      is_last: false,
      block_type: 127,
      length: 0,
      data: Vec::new(),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::FLAC     => {
        match tag!(input, "fLaC") {
          IResult::Done(_, _) => {
            self.state = ParserState::Header;
            ConsumerState::Await(4, 4)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      }
      ParserState::Header   => {
        match header(input) {
          IResult::Done(_, data) => {
            let (is_last, block_type, length) = data;

            self.state      = ParserState::MetaData;
            self.is_last    = is_last;
            self.block_type = block_type;
            self.length     = length;

            ConsumerState::Await(4, length as usize)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      },
      ParserState::MetaData => {
        let length = self.length as usize;

        match block_data(input, self.block_type, self.length) {
          IResult::Done(_, data) => {
            self.data.push(Block {
              is_last: self.is_last,
              length: self.length,
              data: data,
            });

            if self.is_last {
              ConsumerState::ConsumerDone
            } else {
              self.state = ParserState::Header;

              ConsumerState::Await(length, 4)
            }
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, length),
        }
      }
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<|endoftext|>


<commit_before>//! Small Bitset
//!
//! This module defines a struct BitSet<T> encapsulating a bitset built over the type T.
//! T is intended to be a primitive unsigned type. Currently it can be any type between u8 and u32
//!
//! If you would like to add support for larger bitsets in the future, you need to change the trait
//! bound Into<u32> and the u32 in the implementation of max_bits()
use std::mem::size_of;
use std::ops::{Shl, BitOr, Sub, Add};
use std::convert::{Into, From};

/// A small bitset built on a single primitive integer type
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BitSet<T>(pub T);

impl<T> BitSet<T>
where
    T: Into<u32>
        + From<u8>
        + BitOr<T, Output = T>
        + Shl<u8, Output = T>
        + Sub<T, Output = T>
        + Add<T, Output = T>
        + PartialEq
        + Copy,
{
    /// Maximum number of bits supported by this BitSet instance
    pub fn bits() -> usize {
        size_of::<T>() * 8
    }

    /// Maximum number of bits supported by any bitset instance atm.
    pub fn max_bits() -> usize {
        size_of::<u32>() * 8
    }

    /// Check if this BitSet contains the number num
    pub fn contains(&self, num: u8) -> bool {
        assert!((num as usize) < Self::bits());
        assert!((num as usize) < Self::max_bits());
        self.0.into() & (1 << num) != 0
    }

    /// Return the smallest number contained in the bitset or None if empty
    pub fn min(&self) -> Option<u8> {
        if self.0.into() == 0 {
            None
        } else {
            Some(self.0.into().trailing_zeros() as u8)
        }
    }

    /// Return the largest number contained in the bitset or None if empty
    pub fn max(&self) -> Option<u8> {
        if self.0.into() == 0 {
            None
        } else {
            let leading_zeroes = self.0.into().leading_zeros() as usize;
            Some((Self::max_bits() - leading_zeroes - 1) as u8)
        }
    }

    /// Construct a BitSet with the half-open range [lo,hi) filled in
    pub fn from_range(lo: u8, hi: u8) -> BitSet<T> {
        assert!(lo <= hi);
        assert!((hi as usize) <= Self::bits());
        let one: T = T::from(1);
        // I can't just do (one << hi) - one here as the shift may overflow
        let hi_rng = if hi >= 1 {
            (one << (hi - 1)) + ((one << (hi - 1)) - one)
        } else {
            T::from(0)
        };

        let lo_rng = (one << lo) - one;

        BitSet(hi_rng - lo_rng)
    }
}

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

    #[test]
    fn contains() {
        let s = BitSet::<u8>(255);
        for i in 0..7 {
            assert!(s.contains(i));
        }

        let s1 = BitSet::<u8>(0);
        for i in 0..7 {
            assert!(!s1.contains(i));
        }

        let s2 = BitSet::<u8>(127);
        for i in 0..6 {
            assert!(s2.contains(i));
        }
        assert!(!s2.contains(7));

        let s3 = BitSet::<u8>(2 | 4 | 64);
        assert!(!s3.contains(0) && !s3.contains(3) && !s3.contains(4));
        assert!(!s3.contains(5) && !s3.contains(7));
        assert!(s3.contains(1) && s3.contains(2) && s3.contains(6));

        let s4 = BitSet::<u16>(4 | 8 | 256 | 1024);
        assert!(
            !s4.contains(0) && !s4.contains(1) && !s4.contains(4) && !s4.contains(5) &&
                !s4.contains(6) && !s4.contains(7) && !s4.contains(9) && !s4.contains(11)
        );
        assert!(s4.contains(2) && s4.contains(3) && s4.contains(8) && s4.contains(10));
    }

    #[test]
    fn minmax() {
        let s = BitSet::<u8>(255);
        assert_eq!(s.min(), Some(0));
        assert_eq!(s.max(), Some(7));
        assert!(s.min() == Some(0) && s.max() == Some(7));
        let s1 = BitSet::<u8>(0);
        assert!(s1.min() == None && s1.max() == None);
        let s2 = BitSet::<u8>(127);
        assert!(s2.min() == Some(0) && s2.max() == Some(6));
        let s3 = BitSet::<u8>(2 | 4 | 64);
        assert!(s3.min() == Some(1) && s3.max() == Some(6));
        let s4 = BitSet::<u16>(4 | 8 | 256 | 1024);
        assert!(s4.min() == Some(2) && s4.max() == Some(10));
    }

    #[test]
    fn from_range() {
        let s = BitSet::<u8>::from_range(5, 5);
        assert!(s.0 == 0);

        let s = BitSet::<u8>::from_range(0, 8);
        assert!(s.0 == 255);

        let s = BitSet::<u16>::from_range(0, 8);
        assert!(s.0 == 255u16);

        let s = BitSet::<u16>::from_range(0, 16);
        assert!(s.0 == 65535u16);

        let s = BitSet::<u8>::from_range(5, 6);
        assert!(s.0 == 32u8);

        let s = BitSet::<u8>::from_range(3, 7);
        assert!(s.0 == 8 | 16 | 32 | 64);

        let s = BitSet::<u16>::from_range(5, 11);
        assert!(s.0 == 32 | 64 | 128 | 256 | 512 | 1024);
    }
}
<commit_msg>Minor comment cleanups.<commit_after>//! Small Bitset
//!
//! This module defines a struct `BitSet<T>` encapsulating a bitset built over the type T.
//! T is intended to be a primitive unsigned type. Currently it can be any type between u8 and u32
//!
//! If you would like to add support for larger bitsets in the future, you need to change the trait
//! bound Into<u32> and the u32 in the implementation of `max_bits()`.
use std::mem::size_of;
use std::ops::{Shl, BitOr, Sub, Add};
use std::convert::{Into, From};

/// A small bitset built on a single primitive integer type
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BitSet<T>(pub T);

impl<T> BitSet<T>
where
    T: Into<u32>
        + From<u8>
        + BitOr<T, Output = T>
        + Shl<u8, Output = T>
        + Sub<T, Output = T>
        + Add<T, Output = T>
        + PartialEq
        + Copy,
{
    /// Maximum number of bits supported by this BitSet instance
    pub fn bits() -> usize {
        size_of::<T>() * 8
    }

    /// Maximum number of bits supported by any bitset instance atm.
    pub fn max_bits() -> usize {
        size_of::<u32>() * 8
    }

    /// Check if this BitSet contains the number num
    pub fn contains(&self, num: u8) -> bool {
        assert!((num as usize) < Self::bits());
        assert!((num as usize) < Self::max_bits());
        self.0.into() & (1 << num) != 0
    }

    /// Return the smallest number contained in the bitset or None if empty
    pub fn min(&self) -> Option<u8> {
        if self.0.into() == 0 {
            None
        } else {
            Some(self.0.into().trailing_zeros() as u8)
        }
    }

    /// Return the largest number contained in the bitset or None if empty
    pub fn max(&self) -> Option<u8> {
        if self.0.into() == 0 {
            None
        } else {
            let leading_zeroes = self.0.into().leading_zeros() as usize;
            Some((Self::max_bits() - leading_zeroes - 1) as u8)
        }
    }

    /// Construct a BitSet with the half-open range [lo,hi) filled in
    pub fn from_range(lo: u8, hi: u8) -> BitSet<T> {
        assert!(lo <= hi);
        assert!((hi as usize) <= Self::bits());
        let one: T = T::from(1);
        // I can't just do (one << hi) - one here as the shift may overflow
        let hi_rng = if hi >= 1 {
            (one << (hi - 1)) + ((one << (hi - 1)) - one)
        } else {
            T::from(0)
        };

        let lo_rng = (one << lo) - one;

        BitSet(hi_rng - lo_rng)
    }
}

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

    #[test]
    fn contains() {
        let s = BitSet::<u8>(255);
        for i in 0..7 {
            assert!(s.contains(i));
        }

        let s1 = BitSet::<u8>(0);
        for i in 0..7 {
            assert!(!s1.contains(i));
        }

        let s2 = BitSet::<u8>(127);
        for i in 0..6 {
            assert!(s2.contains(i));
        }
        assert!(!s2.contains(7));

        let s3 = BitSet::<u8>(2 | 4 | 64);
        assert!(!s3.contains(0) && !s3.contains(3) && !s3.contains(4));
        assert!(!s3.contains(5) && !s3.contains(7));
        assert!(s3.contains(1) && s3.contains(2) && s3.contains(6));

        let s4 = BitSet::<u16>(4 | 8 | 256 | 1024);
        assert!(
            !s4.contains(0) && !s4.contains(1) && !s4.contains(4) && !s4.contains(5) &&
                !s4.contains(6) && !s4.contains(7) && !s4.contains(9) && !s4.contains(11)
        );
        assert!(s4.contains(2) && s4.contains(3) && s4.contains(8) && s4.contains(10));
    }

    #[test]
    fn minmax() {
        let s = BitSet::<u8>(255);
        assert_eq!(s.min(), Some(0));
        assert_eq!(s.max(), Some(7));
        assert!(s.min() == Some(0) && s.max() == Some(7));
        let s1 = BitSet::<u8>(0);
        assert!(s1.min() == None && s1.max() == None);
        let s2 = BitSet::<u8>(127);
        assert!(s2.min() == Some(0) && s2.max() == Some(6));
        let s3 = BitSet::<u8>(2 | 4 | 64);
        assert!(s3.min() == Some(1) && s3.max() == Some(6));
        let s4 = BitSet::<u16>(4 | 8 | 256 | 1024);
        assert!(s4.min() == Some(2) && s4.max() == Some(10));
    }

    #[test]
    fn from_range() {
        let s = BitSet::<u8>::from_range(5, 5);
        assert!(s.0 == 0);

        let s = BitSet::<u8>::from_range(0, 8);
        assert!(s.0 == 255);

        let s = BitSet::<u16>::from_range(0, 8);
        assert!(s.0 == 255u16);

        let s = BitSet::<u16>::from_range(0, 16);
        assert!(s.0 == 65535u16);

        let s = BitSet::<u8>::from_range(5, 6);
        assert!(s.0 == 32u8);

        let s = BitSet::<u8>::from_range(3, 7);
        assert!(s.0 == 8 | 16 | 32 | 64);

        let s = BitSet::<u16>::from_range(5, 11);
        assert!(s.0 == 32 | 64 | 128 | 256 | 512 | 1024);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro_span)]

use proc_macro::LineColumn;

#[test]
fn test_line_column_ord() {
    let line0_column0 = LineColumn { line: 0, column: 0 };
    let line0_column1 = LineColumn { line: 0, column: 1 };
    let line1_column0 = LineColumn { line: 1, column: 0 };
    assert!(line0_column0 < line0_column1);
    assert!(line0_column1 < line1_column0);
}
<commit_msg>Add Punct PartialEq smoke test<commit_after>#![feature(proc_macro_span)]

use proc_macro::{LineColumn, Punct};

#[test]
fn test_line_column_ord() {
    let line0_column0 = LineColumn { line: 0, column: 0 };
    let line0_column1 = LineColumn { line: 0, column: 1 };
    let line1_column0 = LineColumn { line: 1, column: 0 };
    assert!(line0_column0 < line0_column1);
    assert!(line0_column1 < line1_column0);
}

#[test]
fn test_punct_eq() {
    // Good enough if it typechecks, since proc_macro::Punct can't exist in a test.
    fn _check(punct: Punct) {
        let _ = punct == ':';
    }
}
<|endoftext|>


<commit_before>pub mod utils;
pub mod vertex;

use self::vertex::Vertex;

extern crate winit;
extern crate vulkano;
extern crate vulkano_win;
extern crate cgmath;
extern crate time;

use vulkano_win::VkSurfaceBuild;
use vulkano::buffer::BufferUsage;
use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::buffer::ImmutableBuffer;
use vulkano::buffer::DeviceLocalBuffer;
use vulkano::command_buffer;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::PrimaryCommandBufferBuilder;
use vulkano::command_buffer::Submission;
use vulkano::device::Device;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::Subpass;
use vulkano::instance::Instance;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineParams;
use vulkano::pipeline::blend::Blend;
use vulkano::pipeline::depth_stencil::DepthStencil;
use vulkano::pipeline::input_assembly::InputAssembly;
use vulkano::pipeline::multisample::Multisample;
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::viewport::ViewportsState;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::viewport::Scissor;
use vulkano::swapchain::SurfaceTransform;
use vulkano::swapchain::Swapchain;
use vulkano::pipeline::input_assembly::PrimitiveTopology;
use vulkano::image::SwapchainImage;
use vulkano::device::QueuesIter;
use vulkano::device::Queue;

use std::sync::Arc;
use std::time::Duration;

use std::collections::VecDeque;

use self::utils::fps;

use game_state::{Renderer, Renderable};
use game_state::tree::{ BreadthFirstVisitor, NodeVisitor };
use game_state::state::SceneGraph;

use std::cell::RefCell;
use std::rc::Rc;

//TODO: compile these elsewhere, at build time?
// These shaders are a PITA, generated by build.rs, dependent on OUT_DIR... *barf
// More importantly, these are actually compiled SPIR-V, ignore the glsl file extension on them
mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/assets/shaders/triangle_vs.glsl") }}
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/assets/shaders/triangle_fs.glsl") }}

// TODO: do we want clearcolor settable?
const CLEAR_COLOR: [f32;4] = [0.0, 0.0, 0.0, 1.0];

// TODO: explore more complex options for renderpasses
pub mod render_pass {
	use vulkano::format::Format;
	single_pass_renderpass!{
		attachments: {
			color: {
				load:Clear,
				store:Store,
				format:Format,
			},
			depth: {
			    load: Clear,
			    store: DontCare,
			    format: ::vulkano::format::D16Unorm,
			}
		},
		pass: {
			color: [color],
			depth_stencil: {depth}
		}
	}
}

pub mod pipeline_layout {
    pipeline_layout! {
        set0: {
            uniforms: UniformBuffer<::renderer::vs::ty::Data>
        }
    }
}

pub struct VulkanRenderer {
	instance: Arc<Instance>,
	window: vulkano_win::Window,
	device: Arc<Device>,
	queues: QueuesIter,
	queue: Arc<Queue>,
	swapchain: Arc<Swapchain>,
	images: Vec<Arc<SwapchainImage>>,
	submissions: Vec<Arc<Submission>>,
	pipeline: Arc<GraphicsPipeline<SingleBufferDefinition<Vertex>, pipeline_layout::CustomPipeline, render_pass::CustomRenderPass>>,
	framebuffers: Vec<Arc<Framebuffer<render_pass::CustomRenderPass>>>,
	render_pass: Arc<render_pass::CustomRenderPass>,
	fps: fps::FPS,
    render_layer_queue: VecDeque<Arc<SceneGraph>>,
    pipeline_set: Arc<pipeline_layout::set0::Set>,
    uniform_buffer: Arc<CpuAccessibleBuffer<::renderer::vs::ty::Data>>,
}

impl VulkanRenderer {
	pub fn new(title: &str, h: u32, w: u32) -> Self {
		// Vulkan
		let instance = {
			let extensions = vulkano_win::required_extensions();
			Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
		};

		let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
			.next().expect("No device available.");

		let window = winit::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(h,w)
            .build_vk_surface(&instance).unwrap();

		let queue = physical.queue_families().find(|q| {
			q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false)
		}).expect("Couldn't find a graphical queue family.");

		let (device, mut queues) = {
			let device_ext = vulkano::device::DeviceExtensions {
				khr_swapchain: true,
				.. vulkano::device::DeviceExtensions::none()
			};

			Device::new(&physical, physical.supported_features(), &device_ext,
				[(queue, 0.5)].iter().cloned()
			).expect("Failed to create device.")
		};

		let queue = queues.next().unwrap();

		let (swapchain, images) = {
			let caps = window.surface().get_capabilities(&physical).expect("Failed to get surface capabilities");
			let dimensions = caps.current_extent.unwrap_or([1280, 800]);
			let present = caps.present_modes.iter().next().unwrap();
			let alpha = caps.supported_composite_alpha.iter().next().unwrap();
			let format = caps.supported_formats[0].0;
			Swapchain::new(
				&device,
				&window.surface(),
				2,
				format,
				dimensions,
				1,
				&caps.supported_usage_flags,
				&queue,
				SurfaceTransform::Identity,
				alpha,
				present,
				true,
				None
			).expect("Failed to create swapchain.")
		};

		let vs = vs::Shader::load(&device).expect("failed to create vs shader module");
		let fs = fs::Shader::load(&device).expect("failed to create fs shader module");

		let render_pass = render_pass::CustomRenderPass::new(&device, &render_pass::Formats {
			color: (images[0].format(), 1),
            depth: (vulkano::format::D16Unorm, 1)
		}).unwrap();

        let proj = cgmath::perspective(
            cgmath::Rad(::std::f32::consts::FRAC_PI_2),
            { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 },
            0.01,
            5.0
        );

        // Vulkan uses right-handed coordinates, y positive is down
        let view = cgmath::Matrix4::look_at(
            cgmath::Point3::new(0.5, -1.0, 1.0),   // eye
            cgmath::Point3::new(0.0, 0.5, -1.0),  // center
            cgmath::Vector3::new(0.0, 1.0, 0.0)  // up
        );

        let scale = cgmath::Matrix4::from_scale(1.0);

        let uniform_buffer = CpuAccessibleBuffer::<vs::ty::Data>::from_data(
            &device,
            &vulkano::buffer::BufferUsage::all(),
            Some(queue.family()),
            vs::ty::Data {
                world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                view : (view * scale).into(),
                proj : proj.into(),
            }).expect("failed to create buffer");

        let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);
        let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();
        let pipeline_set = pipeline_layout::set0::Set::new(&descriptor_pool, &pipeline_layout, &pipeline_layout::set0::Descriptors {
            uniforms: &uniform_buffer
        });

		let pipeline = GraphicsPipeline::new(&device, GraphicsPipelineParams {
			vertex_input: SingleBufferDefinition::new(),
			vertex_shader: vs.main_entry_point(),
			input_assembly: InputAssembly {
				topology: PrimitiveTopology::TriangleList,
				primitive_restart_enable: false,
			},
			tessellation: None,
			geometry_shader: None, //&geometry_shader,
			viewport: ViewportsState::Fixed {
				data: vec![(
					Viewport {
						origin: [0.0, 0.0],
						depth_range: 0.0 .. 1.0,
						dimensions: [images[0].dimensions()[0] as f32,
						images[0].dimensions()[1] as f32],
					},
					Scissor::irrelevant()
				)],
			},
			raster: Default::default(),
			multisample: Multisample::disabled(),
			fragment_shader: fs.main_entry_point(),
			depth_stencil: DepthStencil::disabled(),
			blend: Blend::pass_through(),
			layout: &pipeline_layout,
			render_pass: Subpass::from(&render_pass, 0).unwrap(),
		}).unwrap();

        let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(
            &device,
            images[0].dimensions(),
            vulkano::format::D16Unorm
        ).unwrap();

		let framebuffers = images.iter().map(|image| {
			let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
			Framebuffer::new(&render_pass, dimensions, render_pass::AList {
				color: &image,
                depth: &depth_buffer
			}).unwrap()
		}).collect::<Vec<_>>();

		let submissions:Vec<Arc<Submission>> = Vec::new();

		VulkanRenderer {
			// render
			device: device,
			queue: queue,
			swapchain: swapchain,
			submissions: submissions,
			pipeline: pipeline,
			framebuffers: framebuffers,
			render_pass: render_pass,

			//individually exposed
			images: images,
			queues: queues,
			instance: instance.clone(),
			fps: fps::FPS::new(),
			window: window,
            render_layer_queue: VecDeque::new(),
            pipeline_set: pipeline_set,
            uniform_buffer: uniform_buffer,
		}

	}

	pub fn instance(&self) -> Arc<Instance> {
		self.instance.clone()
	}

	pub fn queues(&mut self) -> &mut QueuesIter {
		&mut self.queues
	}

	pub fn images(&mut self) -> &Vec<Arc<SwapchainImage>> {
		&mut self.images
	}

	pub fn window(&self) -> &vulkano_win::Window {
		&self.window
	}

	pub fn native_window(&self) -> &winit::Window {
		&self.window.window()
	}

    pub fn create_cpu_buffer<T:'static+Sized+Clone>(&self, data: &Vec<T>) -> Arc<CpuAccessibleBuffer<[T]>> {
        CpuAccessibleBuffer::from_iter(
            &self.device,
            &BufferUsage::all(),
            Some(self.queue.family()),
            data.iter().cloned()
        ).expect("Unable to create buffer")
    }

    fn render(&mut self) {

        // TODO: create buffers for and setup draw calls

        self.submissions.retain(|s| s.destroying_would_block());
        let image_num = self.swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        // begin the command buffer
        let mut cmd_buffer_build = PrimaryCommandBufferBuilder::new(&self.device, self.queue.family())
            .draw_inline(
                &self.render_pass,
                &self.framebuffers[image_num],
                render_pass::ClearValues {
                    color: CLEAR_COLOR,
                    depth: 1.0,
                });

		let cell = Rc::new(RefCell::new(cmd_buffer_build));

        let mut rad = 0.00001;

        // TODO: do away with this renderable queue
        loop {
            match self.render_layer_queue.pop_front() {
                Some(next_layer) => {

                    let mut visitor = BreadthFirstVisitor::new(next_layer.root.clone());
					while visitor.has_next() {
						visitor.visit(|renderable| {
							// println!("got renderable");
							let mesh = renderable.get_mesh();

							let world_mat = renderable.get_world_matrix();
							let view_mat = renderable.get_view_matrix();

							let vertices: Vec<Vertex> = mesh.vertices.iter().map(|x| {
								Vertex::from(*x)
							}).collect();

							let indices = &mesh.indices;

							let vert_buffer = self.create_cpu_buffer(&vertices);
							let index_buffer = self.create_cpu_buffer(indices);

							let mut buffer_content = self.uniform_buffer.write(
								Duration::new(1, 0)
							).unwrap();

							rad += 0.1;
							let current_view: cgmath::Matrix4<f32> = buffer_content.view.into();
							let rotation = cgmath::Matrix4::from_angle_y(cgmath::Rad(rad));
							buffer_content.view = (current_view * rotation).into();
							buffer_content.world = world_mat.clone().into();

							//println!("building indexed command buffer");
							commands.push_back(cmd_buffer_build.draw_indexed(
								&self.pipeline,
								&vert_buffer,
								&index_buffer,
								&DynamicState::none(), &self.pipeline_set, &()
							));
						});
					}
                },
                None => { break; }
            }
        }
        //println!("draw_end() for command buffer");
        let cmd_buffer_build = commands.get(0).unwrap().draw_end();

        //println!("finalizing command buffer");
        let cmd_buffer = cmd_buffer_build.build();

        //println!("submitting command buffer");
        self.submissions.push(command_buffer::submit(&cmd_buffer, &self.queue).unwrap());

        //println!("presenting");
        self.swapchain.present(&self.queue, image_num).unwrap();

        self.fps.update();
    }

    #[allow(dead_code)]
    fn fps(&self) -> f32 {
        self.fps.get()
    }

}

impl Renderer for VulkanRenderer {
    fn queue_render_layer(&mut self, layer: Arc<SceneGraph>) {
        self.render_layer_queue.push_back(layer);
    }

    fn present(&mut self) {
        self.render();
    }
}

<commit_msg>stuck on moving out of command buffer builder<commit_after>pub mod utils;
pub mod vertex;

use self::vertex::Vertex;

extern crate winit;
extern crate vulkano;
extern crate vulkano_win;
extern crate cgmath;
extern crate time;

use vulkano_win::VkSurfaceBuild;
use vulkano::buffer::BufferUsage;
use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::buffer::ImmutableBuffer;
use vulkano::buffer::DeviceLocalBuffer;
use vulkano::command_buffer;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::PrimaryCommandBufferBuilder;
use vulkano::command_buffer::Submission;
use vulkano::device::Device;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::Subpass;
use vulkano::instance::Instance;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineParams;
use vulkano::pipeline::blend::Blend;
use vulkano::pipeline::depth_stencil::DepthStencil;
use vulkano::pipeline::input_assembly::InputAssembly;
use vulkano::pipeline::multisample::Multisample;
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::viewport::ViewportsState;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::viewport::Scissor;
use vulkano::swapchain::SurfaceTransform;
use vulkano::swapchain::Swapchain;
use vulkano::pipeline::input_assembly::PrimitiveTopology;
use vulkano::image::SwapchainImage;
use vulkano::device::QueuesIter;
use vulkano::device::Queue;

use std::sync::Arc;
use std::time::Duration;

use std::collections::VecDeque;

use self::utils::fps;

use game_state::{Renderer, Renderable};
use game_state::tree::{ BreadthFirstVisitor, NodeVisitor };
use game_state::state::SceneGraph;

use std::cell::RefCell;
use std::rc::Rc;

//TODO: compile these elsewhere, at build time?
// These shaders are a PITA, generated by build.rs, dependent on OUT_DIR... *barf
// More importantly, these are actually compiled SPIR-V, ignore the glsl file extension on them
mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/assets/shaders/triangle_vs.glsl") }}
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/assets/shaders/triangle_fs.glsl") }}

// TODO: do we want clearcolor settable?
const CLEAR_COLOR: [f32;4] = [0.0, 0.0, 0.0, 1.0];

// TODO: explore more complex options for renderpasses
pub mod render_pass {
	use vulkano::format::Format;
	single_pass_renderpass!{
		attachments: {
			color: {
				load:Clear,
				store:Store,
				format:Format,
			},
			depth: {
			    load: Clear,
			    store: DontCare,
			    format: ::vulkano::format::D16Unorm,
			}
		},
		pass: {
			color: [color],
			depth_stencil: {depth}
		}
	}
}

pub mod pipeline_layout {
    pipeline_layout! {
        set0: {
            uniforms: UniformBuffer<::renderer::vs::ty::Data>
        }
    }
}

pub struct VulkanRenderer {
	instance: Arc<Instance>,
	window: vulkano_win::Window,
	device: Arc<Device>,
	queues: QueuesIter,
	queue: Arc<Queue>,
	swapchain: Arc<Swapchain>,
	images: Vec<Arc<SwapchainImage>>,
	submissions: Vec<Arc<Submission>>,
	pipeline: Arc<GraphicsPipeline<SingleBufferDefinition<Vertex>, pipeline_layout::CustomPipeline, render_pass::CustomRenderPass>>,
	framebuffers: Vec<Arc<Framebuffer<render_pass::CustomRenderPass>>>,
	render_pass: Arc<render_pass::CustomRenderPass>,
	fps: fps::FPS,
    render_layer_queue: VecDeque<Arc<SceneGraph>>,
    pipeline_set: Arc<pipeline_layout::set0::Set>,
    uniform_buffer: Arc<CpuAccessibleBuffer<::renderer::vs::ty::Data>>,
}

impl VulkanRenderer {
	pub fn new(title: &str, h: u32, w: u32) -> Self {
		// Vulkan
		let instance = {
			let extensions = vulkano_win::required_extensions();
			Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
		};

		let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
			.next().expect("No device available.");

		let window = winit::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(h,w)
            .build_vk_surface(&instance).unwrap();

		let queue = physical.queue_families().find(|q| {
			q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false)
		}).expect("Couldn't find a graphical queue family.");

		let (device, mut queues) = {
			let device_ext = vulkano::device::DeviceExtensions {
				khr_swapchain: true,
				.. vulkano::device::DeviceExtensions::none()
			};

			Device::new(&physical, physical.supported_features(), &device_ext,
				[(queue, 0.5)].iter().cloned()
			).expect("Failed to create device.")
		};

		let queue = queues.next().unwrap();

		let (swapchain, images) = {
			let caps = window.surface().get_capabilities(&physical).expect("Failed to get surface capabilities");
			let dimensions = caps.current_extent.unwrap_or([1280, 800]);
			let present = caps.present_modes.iter().next().unwrap();
			let alpha = caps.supported_composite_alpha.iter().next().unwrap();
			let format = caps.supported_formats[0].0;
			Swapchain::new(
				&device,
				&window.surface(),
				2,
				format,
				dimensions,
				1,
				&caps.supported_usage_flags,
				&queue,
				SurfaceTransform::Identity,
				alpha,
				present,
				true,
				None
			).expect("Failed to create swapchain.")
		};

		let vs = vs::Shader::load(&device).expect("failed to create vs shader module");
		let fs = fs::Shader::load(&device).expect("failed to create fs shader module");

		let render_pass = render_pass::CustomRenderPass::new(&device, &render_pass::Formats {
			color: (images[0].format(), 1),
            depth: (vulkano::format::D16Unorm, 1)
		}).unwrap();

        let proj = cgmath::perspective(
            cgmath::Rad(::std::f32::consts::FRAC_PI_2),
            { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 },
            0.01,
            5.0
        );

        // Vulkan uses right-handed coordinates, y positive is down
        let view = cgmath::Matrix4::look_at(
            cgmath::Point3::new(0.5, -1.0, 1.0),   // eye
            cgmath::Point3::new(0.0, 0.5, -1.0),  // center
            cgmath::Vector3::new(0.0, 1.0, 0.0)  // up
        );

        let scale = cgmath::Matrix4::from_scale(1.0);

        let uniform_buffer = CpuAccessibleBuffer::<vs::ty::Data>::from_data(
            &device,
            &vulkano::buffer::BufferUsage::all(),
            Some(queue.family()),
            vs::ty::Data {
                world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                view : (view * scale).into(),
                proj : proj.into(),
            }).expect("failed to create buffer");

        let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);
        let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();
        let pipeline_set = pipeline_layout::set0::Set::new(&descriptor_pool, &pipeline_layout, &pipeline_layout::set0::Descriptors {
            uniforms: &uniform_buffer
        });

		let pipeline = GraphicsPipeline::new(&device, GraphicsPipelineParams {
			vertex_input: SingleBufferDefinition::new(),
			vertex_shader: vs.main_entry_point(),
			input_assembly: InputAssembly {
				topology: PrimitiveTopology::TriangleList,
				primitive_restart_enable: false,
			},
			tessellation: None,
			geometry_shader: None, //&geometry_shader,
			viewport: ViewportsState::Fixed {
				data: vec![(
					Viewport {
						origin: [0.0, 0.0],
						depth_range: 0.0 .. 1.0,
						dimensions: [images[0].dimensions()[0] as f32,
						images[0].dimensions()[1] as f32],
					},
					Scissor::irrelevant()
				)],
			},
			raster: Default::default(),
			multisample: Multisample::disabled(),
			fragment_shader: fs.main_entry_point(),
			depth_stencil: DepthStencil::disabled(),
			blend: Blend::pass_through(),
			layout: &pipeline_layout,
			render_pass: Subpass::from(&render_pass, 0).unwrap(),
		}).unwrap();

        let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(
            &device,
            images[0].dimensions(),
            vulkano::format::D16Unorm
        ).unwrap();

		let framebuffers = images.iter().map(|image| {
			let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
			Framebuffer::new(&render_pass, dimensions, render_pass::AList {
				color: &image,
                depth: &depth_buffer
			}).unwrap()
		}).collect::<Vec<_>>();

		let submissions:Vec<Arc<Submission>> = Vec::new();

		VulkanRenderer {
			// render
			device: device,
			queue: queue,
			swapchain: swapchain,
			submissions: submissions,
			pipeline: pipeline,
			framebuffers: framebuffers,
			render_pass: render_pass,

			//individually exposed
			images: images,
			queues: queues,
			instance: instance.clone(),
			fps: fps::FPS::new(),
			window: window,
            render_layer_queue: VecDeque::new(),
            pipeline_set: pipeline_set,
            uniform_buffer: uniform_buffer,
		}

	}

	pub fn instance(&self) -> Arc<Instance> {
		self.instance.clone()
	}

	pub fn queues(&mut self) -> &mut QueuesIter {
		&mut self.queues
	}

	pub fn images(&mut self) -> &Vec<Arc<SwapchainImage>> {
		&mut self.images
	}

	pub fn window(&self) -> &vulkano_win::Window {
		&self.window
	}

	pub fn native_window(&self) -> &winit::Window {
		&self.window.window()
	}

    pub fn create_cpu_buffer<T:'static+Sized+Clone>(&self, data: &Vec<T>) -> Arc<CpuAccessibleBuffer<[T]>> {
        CpuAccessibleBuffer::from_iter(
            &self.device,
            &BufferUsage::all(),
            Some(self.queue.family()),
            data.iter().cloned()
        ).expect("Unable to create buffer")
    }

    fn render(&mut self) {

        // TODO: create buffers for and setup draw calls

        self.submissions.retain(|s| s.destroying_would_block());
        let image_num = self.swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        // begin the command buffer
        let mut cmd_buffer_build = PrimaryCommandBufferBuilder::new(&self.device, self.queue.family())
            .draw_inline(
                &self.render_pass,
                &self.framebuffers[image_num],
                render_pass::ClearValues {
                    color: CLEAR_COLOR,
                    depth: 1.0,
                });

        let mut rad = 0.00001;

		let mut commands = VecDeque::new();

        // TODO: do away with this renderable queue
        loop {
            match self.render_layer_queue.pop_front() {
                Some(next_layer) => {

                    let mut visitor = BreadthFirstVisitor::new(next_layer.root.clone());
					while visitor.has_next() {
						visitor.visit(|renderable| {
							// println!("got renderable");
							let mesh = renderable.get_mesh();

							let world_mat = renderable.get_world_matrix();
							let view_mat = renderable.get_view_matrix();

							let vertices: Vec<Vertex> = mesh.vertices.iter().map(|x| {
								Vertex::from(*x)
							}).collect();

							let indices = &mesh.indices;

							let vert_buffer = self.create_cpu_buffer(&vertices);
							let index_buffer = self.create_cpu_buffer(indices);

							let mut buffer_content = self.uniform_buffer.write(
								Duration::new(1, 0)
							).unwrap();

							rad += 0.1;
							let current_view: cgmath::Matrix4<f32> = buffer_content.view.into();
							let rotation = cgmath::Matrix4::from_angle_y(cgmath::Rad(rad));
							buffer_content.view = (current_view * rotation).into();
							buffer_content.world = world_mat.clone().into();

							//println!("building indexed command buffer");
							commands.push_back(cmd_buffer_build.draw_indexed(
								&self.pipeline,
								&vert_buffer,
								&index_buffer,
								&DynamicState::none(), &self.pipeline_set, &()
							));
						});
					}
                },
                None => { break; }
            }
        }
        //println!("draw_end() for command buffer");
        let cmd_buffer_build = commands.get(0).unwrap().draw_end();

        //println!("finalizing command buffer");
        let cmd_buffer = cmd_buffer_build.build();

        //println!("submitting command buffer");
        self.submissions.push(command_buffer::submit(&cmd_buffer, &self.queue).unwrap());

        //println!("presenting");
        self.swapchain.present(&self.queue, image_num).unwrap();

        self.fps.update();
    }

    #[allow(dead_code)]
    fn fps(&self) -> f32 {
        self.fps.get()
    }

}

impl Renderer for VulkanRenderer {
    fn queue_render_layer(&mut self, layer: Arc<SceneGraph>) {
        self.render_layer_queue.push_back(layer);
    }

    fn present(&mut self) {
        self.render();
    }
}

<|endoftext|>