<commit_before>//! Generator of Rust-Qt crates.
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust/tree/master/qt_generator/qt_generator)
//! for more information.

#![allow(clippy::collapsible_if)]

use crate::lib_configs::make_config;
use log::{error, info};
use qt_ritual_common::all_crate_names;
use ritual::processor;
use ritual::workspace::Workspace;
use ritual_common::errors::{FancyUnwrap, Result};
use ritual_common::file_utils::canonicalize;
use ritual_common::file_utils::path_to_str;
use std::path::PathBuf;
use structopt::StructOpt;

mod detect_signal_argument_types;
mod detect_signals_and_slots;
mod doc_decoder;
mod doc_parser;
mod fix_header_names;
mod lib_configs;
mod versions;

#[cfg(test)]
mod test_moqt;

use flexi_logger::{Duplicate, LevelFilter, LogSpecification, Logger};

#[derive(Debug, StructOpt)]
/// Generates rust_qt crates using ritual.
/// See https://github.com/rust-qt/cpp_to_rust for more details.
struct Options {
    #[structopt(parse(from_os_str))]
    /// Directory for output and temporary files
    workspace: PathBuf,
    #[structopt(long = "local-paths")]
    /// Write local paths to `ritual` crates in generated `Cargo.toml`
    local_paths: Option<bool>,
    #[structopt(long = "delete-database")]
    /// Delete previously created database before processing
    delete_database: bool,
    #[structopt(short = "c", long = "crates", required = true)]
    /// Crates to process (e.g. `qt_core`)
    crates: Vec<String>,
    #[structopt(short = "o", long = "operations", required = true)]
    /// Operations to perform
    operations: Vec<String>,
}

fn run(options: Options) -> Result<()> {
    let workspace_path = canonicalize(options.workspace)?;

    let mut workspace = Workspace::new(workspace_path.clone())?;

    Logger::with(LogSpecification::default(LevelFilter::Trace).build())
        .log_to_file()
        .directory(path_to_str(&workspace.log_path()?)?)
        .print_message()
        .duplicate_to_stderr(Duplicate::Info)
        .start()
        .unwrap_or_else(|e| panic!("Logger initialization failed: {}", e));

    info!("Workspace: {}", workspace_path.display());

    if let Some(local_paths) = options.local_paths {
        workspace.set_write_dependencies_local_paths(local_paths)?;
    }

    let mut was_any_action = false;

    let final_crates = if options.crates.iter().any(|x| *x == "all") {
        all_crate_names().to_vec()
    } else {
        options.crates.iter().map(|s| s.as_str()).collect()
    };

    let operations: Vec<_> = options
        .operations
        .iter()
        .map(|s| s.to_lowercase())
        .collect();

    if operations.is_empty() {
        error!("No action requested. Run \"qt_generator --help\".");
        return Ok(());
    }

    for crate_name in &final_crates {
        if options.delete_database {
            workspace.delete_database_if_exists(&crate_name)?;
        }

        let config = make_config(&crate_name)?;
        was_any_action = true;
        processor::process(&mut workspace, &config, &operations)?;
    }

    //workspace.save_data()?;
    if was_any_action {
        info!("qt_generator finished");
    } else {
        error!("No action requested. Run \"qt_generator --help\".");
    }
    Ok(())
}

pub fn main() {
    run(Options::from_args()).fancy_unwrap();
}
<commit_msg>temporarily disable test_moqt on windows and macos<commit_after>//! Generator of Rust-Qt crates.
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust/tree/master/qt_generator/qt_generator)
//! for more information.

#![allow(clippy::collapsible_if)]

use crate::lib_configs::make_config;
use log::{error, info};
use qt_ritual_common::all_crate_names;
use ritual::processor;
use ritual::workspace::Workspace;
use ritual_common::errors::{FancyUnwrap, Result};
use ritual_common::file_utils::canonicalize;
use ritual_common::file_utils::path_to_str;
use std::path::PathBuf;
use structopt::StructOpt;

mod detect_signal_argument_types;
mod detect_signals_and_slots;
mod doc_decoder;
mod doc_parser;
mod fix_header_names;
mod lib_configs;
mod versions;

#[cfg(test)]
#[cfg(target_os = "linux")] // TODO: fix on Windows and MacOS
mod test_moqt;

use flexi_logger::{Duplicate, LevelFilter, LogSpecification, Logger};

#[derive(Debug, StructOpt)]
/// Generates rust_qt crates using ritual.
/// See https://github.com/rust-qt/cpp_to_rust for more details.
struct Options {
    #[structopt(parse(from_os_str))]
    /// Directory for output and temporary files
    workspace: PathBuf,
    #[structopt(long = "local-paths")]
    /// Write local paths to `ritual` crates in generated `Cargo.toml`
    local_paths: Option<bool>,
    #[structopt(long = "delete-database")]
    /// Delete previously created database before processing
    delete_database: bool,
    #[structopt(short = "c", long = "crates", required = true)]
    /// Crates to process (e.g. `qt_core`)
    crates: Vec<String>,
    #[structopt(short = "o", long = "operations", required = true)]
    /// Operations to perform
    operations: Vec<String>,
}

fn run(options: Options) -> Result<()> {
    let workspace_path = canonicalize(options.workspace)?;

    let mut workspace = Workspace::new(workspace_path.clone())?;

    Logger::with(LogSpecification::default(LevelFilter::Trace).build())
        .log_to_file()
        .directory(path_to_str(&workspace.log_path()?)?)
        .print_message()
        .duplicate_to_stderr(Duplicate::Info)
        .start()
        .unwrap_or_else(|e| panic!("Logger initialization failed: {}", e));

    info!("Workspace: {}", workspace_path.display());

    if let Some(local_paths) = options.local_paths {
        workspace.set_write_dependencies_local_paths(local_paths)?;
    }

    let mut was_any_action = false;

    let final_crates = if options.crates.iter().any(|x| *x == "all") {
        all_crate_names().to_vec()
    } else {
        options.crates.iter().map(|s| s.as_str()).collect()
    };

    let operations: Vec<_> = options
        .operations
        .iter()
        .map(|s| s.to_lowercase())
        .collect();

    if operations.is_empty() {
        error!("No action requested. Run \"qt_generator --help\".");
        return Ok(());
    }

    for crate_name in &final_crates {
        if options.delete_database {
            workspace.delete_database_if_exists(&crate_name)?;
        }

        let config = make_config(&crate_name)?;
        was_any_action = true;
        processor::process(&mut workspace, &config, &operations)?;
    }

    //workspace.save_data()?;
    if was_any_action {
        info!("qt_generator finished");
    } else {
        error!("No action requested. Run \"qt_generator --help\".");
    }
    Ok(())
}

pub fn main() {
    run(Options::from_args()).fancy_unwrap();
}
<|endoftext|>


<commit_before>use std::rand::{task_rng, Rng, SeedableRng, Isaac64Rng};
use std::sync::Arc;
use raytracer::compositor::composite;
use raytracer::{Ray, Tile};
use scene::{Camera, Scene};
use vec3::Vec3;

pub struct Renderer {
    pub reflect_depth: int,  // Maximum reflection recursions.
    pub refract_depth: int,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub use_octree: bool,    // Unimplemented. Use octree/k-d tree?
    pub shadow_samples: int, // Number of samples for soft shadows and area lights.
    pub pixel_samples: int,  // The square of this is the number of samples per pixel.
    pub tasks: int           // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, scene: Scene) -> Vec<Vec3> {
        let mut tiles = Vec::with_capacity(self.tasks as uint);
        let tiles_per_side = (self.tasks as f64).sqrt().ceil() as int;
        let tile_width  = (camera.image_width  as f64 / tiles_per_side as f64) as int;
        let tile_height = (camera.image_height as f64 / tiles_per_side as f64) as int;

        let shared_scene = Arc::new(scene);
        let (tx, rx) = channel();

        for tile_x in range(0, tiles_per_side) {
            for tile_y in range(0, tiles_per_side) {
                let scene_local = shared_scene.clone();
                let child_tx = tx.clone();

                let shadow_samples_local = self.shadow_samples;
                let pixel_samples_local = self.pixel_samples;
                let reflect_depth_local = self.reflect_depth;
                let refract_depth_local = self.refract_depth;

                let start_x = tile_x * tile_width;
                let start_y = tile_y * tile_height;
                let end_x = start_x + tile_width;
                let end_y = start_y + tile_height;

                spawn(proc() {
                    child_tx.send(Renderer::render_tile(camera,
                                                        scene_local.deref(),
                                                        shadow_samples_local,
                                                        pixel_samples_local,
                                                        reflect_depth_local,
                                                        refract_depth_local,
                                                        start_x, start_y,
                                                        end_x, end_y));
                });

            }
        }

        for _ in range(0, tiles_per_side * tiles_per_side) {
            tiles.push(rx.recv())
        }

        composite(tiles, camera.image_width, camera.image_height)
    }

    fn render_tile(camera: Camera,
                   scene: &Scene,
                   shadow_samples: int,
                   pixel_samples: int,
                   reflect_depth: int,
                   refract_depth: int,
                   from_x: int,
                   from_y: int,
                   to_x: int,
                   to_y: int)
                   -> Tile {
        let width  = to_x - from_x;
        let height = to_y - from_y;
        let tile_size = width * height;
        let mut image_data: Vec<Vec3> = Vec::with_capacity(tile_size as uint);

		let mut random_data = [0u64, ..64];
		for i in range(0u, 64u) {
			random_data[i] = task_rng().next_u64();
		}
		let mut rng: Isaac64Rng = SeedableRng::from_seed(random_data.clone());

        for y in range(from_y, to_y) {
            for x in range(from_x, to_x) {
                let mut color = Vec3::zero();

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;

                for y_subpixel in range(0, pixel_samples) {
                    for x_subpixel in range(0, pixel_samples) {
                        let mut j_x = x as f64;
                        let mut j_y = y as f64;

                        // Don't jitter if not antialiasing
                        if pixel_samples > 1 {
                            j_x = j_x + x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                            j_y = j_y + y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                        }

                        let ray = camera.get_ray(j_x, j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples, reflect_depth, refract_depth, false);
                        color = color + result.scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }

                image_data.push(Vec3 {
                    x: color.x,
                    y: color.y,
                    z: color.z
                });
            }
        }

        Tile {
            from_x: from_x,
            from_y: from_y,
            to_x: to_x,
            to_y: to_y,
            data: image_data
        }
    }

    fn trace(scene: &Scene,
             ray: &Ray,
             shadow_samples: int,
             reflect_depth: int,
             refract_depth: int,
             inside: bool)
             -> Vec3 {
        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }
        let epsilon = ::std::f64::EPSILON * 10000.0;

        match ray.get_nearest_hit(scene) {
            Some(nearest_hit) => {
                let n = nearest_hit.n.unit();
                let i = (ray.direction.scale(-1.0)).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let mut shadow = Vec3::zero();

                    if shadow_samples > 0 {
                        // Point light speedup
                        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };

                        // Take average shadow color after jittering/sampling light position
                        for _ in range(0, shadow_sample_tries) {
                            // L has to be a unit vector for t_max 1:1 correspondence to
                            // distance to light to work. Shadow feelers only search up
                            // until light source.
                            let sampled_light_position = light.position();
                            let shadow_l = (sampled_light_position - nearest_hit.position).unit();
                            let shadow_ray = Ray {origin: nearest_hit.position, direction: shadow_l};
                            let distance_to_light = (sampled_light_position - nearest_hit.position).len();

                            // Check against candidate primitives in scene for occlusion
                            // and multiply shadow color by occluders' shadow colors
                            shadow = shadow + scene.prims.iter().fold(Vec3::one(), |shadow_acc, prim| {
                                let occlusion = prim.intersects(&shadow_ray, epsilon, distance_to_light);
                                match occlusion {
                                    Some(occulusion) => {shadow_acc * occulusion.material.transmission()}
                                    None => shadow_acc
                                }
                            });
                        }

                        shadow = shadow.scale(1.0 / shadow_sample_tries as f64);
                    } else {
                        shadow = Vec3::one();
                    }

                    let l = (light.center() - nearest_hit.position).unit();

                    color_acc + light.color() * nearest_hit.material.sample(n, i, l) * shadow
                });

                // Global reflection
                if nearest_hit.material.is_reflective() {
                    let r = Vec3::reflect(&i, &n);
                    let reflect_ray = Ray {origin: nearest_hit.position, direction: r};
                    let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples, reflect_depth - 1, refract_depth, inside);

                    result = result + nearest_hit.material.global_specular(&reflection);
                }

                // Global refraction
                if nearest_hit.material.is_refractive() {
                    let t = Vec3::refract(&i, &n, nearest_hit.material.ior(), inside);
                    let refract_ray = Ray {origin: nearest_hit.position + t.scale(epsilon), direction: t};
                    let refraction = Renderer::trace(scene, &refract_ray, shadow_samples, reflect_depth, refract_depth, !inside);

                    result = result + nearest_hit.material.global_transmissive(&refraction);
                }

                result
            }

            None => {scene.background}
        }
    }
}
<commit_msg>Tabs → spaces in renderer.rs<commit_after>use std::rand::{task_rng, Rng, SeedableRng, Isaac64Rng};
use std::sync::Arc;
use raytracer::compositor::composite;
use raytracer::{Ray, Tile};
use scene::{Camera, Scene};
use vec3::Vec3;

pub struct Renderer {
    pub reflect_depth: int,  // Maximum reflection recursions.
    pub refract_depth: int,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub use_octree: bool,    // Unimplemented. Use octree/k-d tree?
    pub shadow_samples: int, // Number of samples for soft shadows and area lights.
    pub pixel_samples: int,  // The square of this is the number of samples per pixel.
    pub tasks: int           // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, scene: Scene) -> Vec<Vec3> {
        let mut tiles = Vec::with_capacity(self.tasks as uint);
        let tiles_per_side = (self.tasks as f64).sqrt().ceil() as int;
        let tile_width  = (camera.image_width  as f64 / tiles_per_side as f64) as int;
        let tile_height = (camera.image_height as f64 / tiles_per_side as f64) as int;

        let shared_scene = Arc::new(scene);
        let (tx, rx) = channel();

        for tile_x in range(0, tiles_per_side) {
            for tile_y in range(0, tiles_per_side) {
                let scene_local = shared_scene.clone();
                let child_tx = tx.clone();

                let shadow_samples_local = self.shadow_samples;
                let pixel_samples_local = self.pixel_samples;
                let reflect_depth_local = self.reflect_depth;
                let refract_depth_local = self.refract_depth;

                let start_x = tile_x * tile_width;
                let start_y = tile_y * tile_height;
                let end_x = start_x + tile_width;
                let end_y = start_y + tile_height;

                spawn(proc() {
                    child_tx.send(Renderer::render_tile(camera,
                                                        scene_local.deref(),
                                                        shadow_samples_local,
                                                        pixel_samples_local,
                                                        reflect_depth_local,
                                                        refract_depth_local,
                                                        start_x, start_y,
                                                        end_x, end_y));
                });

            }
        }

        for _ in range(0, tiles_per_side * tiles_per_side) {
            tiles.push(rx.recv())
        }

        composite(tiles, camera.image_width, camera.image_height)
    }

    fn render_tile(camera: Camera,
                   scene: &Scene,
                   shadow_samples: int,
                   pixel_samples: int,
                   reflect_depth: int,
                   refract_depth: int,
                   from_x: int,
                   from_y: int,
                   to_x: int,
                   to_y: int)
                   -> Tile {
        let width  = to_x - from_x;
        let height = to_y - from_y;
        let tile_size = width * height;
        let mut image_data: Vec<Vec3> = Vec::with_capacity(tile_size as uint);

        let mut random_data = [0u64, ..64];
        for i in range(0u, 64u) {
            random_data[i] = task_rng().next_u64();
        }
        let mut rng: Isaac64Rng = SeedableRng::from_seed(random_data.clone());

        for y in range(from_y, to_y) {
            for x in range(from_x, to_x) {
                let mut color = Vec3::zero();

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;

                for y_subpixel in range(0, pixel_samples) {
                    for x_subpixel in range(0, pixel_samples) {
                        let mut j_x = x as f64;
                        let mut j_y = y as f64;

                        // Don't jitter if not antialiasing
                        if pixel_samples > 1 {
                            j_x = j_x + x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                            j_y = j_y + y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                        }

                        let ray = camera.get_ray(j_x, j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples, reflect_depth, refract_depth, false);
                        color = color + result.scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }

                image_data.push(Vec3 {
                    x: color.x,
                    y: color.y,
                    z: color.z
                });
            }
        }

        Tile {
            from_x: from_x,
            from_y: from_y,
            to_x: to_x,
            to_y: to_y,
            data: image_data
        }
    }

    fn trace(scene: &Scene,
             ray: &Ray,
             shadow_samples: int,
             reflect_depth: int,
             refract_depth: int,
             inside: bool)
             -> Vec3 {
        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }
        let epsilon = ::std::f64::EPSILON * 10000.0;

        match ray.get_nearest_hit(scene) {
            Some(nearest_hit) => {
                let n = nearest_hit.n.unit();
                let i = (ray.direction.scale(-1.0)).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let mut shadow = Vec3::zero();

                    if shadow_samples > 0 {
                        // Point light speedup
                        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };

                        // Take average shadow color after jittering/sampling light position
                        for _ in range(0, shadow_sample_tries) {
                            // L has to be a unit vector for t_max 1:1 correspondence to
                            // distance to light to work. Shadow feelers only search up
                            // until light source.
                            let sampled_light_position = light.position();
                            let shadow_l = (sampled_light_position - nearest_hit.position).unit();
                            let shadow_ray = Ray {origin: nearest_hit.position, direction: shadow_l};
                            let distance_to_light = (sampled_light_position - nearest_hit.position).len();

                            // Check against candidate primitives in scene for occlusion
                            // and multiply shadow color by occluders' shadow colors
                            shadow = shadow + scene.prims.iter().fold(Vec3::one(), |shadow_acc, prim| {
                                let occlusion = prim.intersects(&shadow_ray, epsilon, distance_to_light);
                                match occlusion {
                                    Some(occulusion) => {shadow_acc * occulusion.material.transmission()}
                                    None => shadow_acc
                                }
                            });
                        }

                        shadow = shadow.scale(1.0 / shadow_sample_tries as f64);
                    } else {
                        shadow = Vec3::one();
                    }

                    let l = (light.center() - nearest_hit.position).unit();

                    color_acc + light.color() * nearest_hit.material.sample(n, i, l) * shadow
                });

                // Global reflection
                if nearest_hit.material.is_reflective() {
                    let r = Vec3::reflect(&i, &n);
                    let reflect_ray = Ray {origin: nearest_hit.position, direction: r};
                    let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples, reflect_depth - 1, refract_depth, inside);

                    result = result + nearest_hit.material.global_specular(&reflection);
                }

                // Global refraction
                if nearest_hit.material.is_refractive() {
                    let t = Vec3::refract(&i, &n, nearest_hit.material.ior(), inside);
                    let refract_ray = Ray {origin: nearest_hit.position + t.scale(epsilon), direction: t};
                    let refraction = Renderer::trace(scene, &refract_ray, shadow_samples, reflect_depth, refract_depth, !inside);

                    result = result + nearest_hit.material.global_transmissive(&refraction);
                }

                result
            }

            None => {scene.background}
        }
    }
}
<|endoftext|>


<commit_before>extern crate turtle;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    for _ in 0..36 {
        square(&mut turtle);
        turtle.right(10.0);
    }
}

fn square(turtle: &mut Turtle) {
    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}
<commit_msg>Colored squares example<commit_after>extern crate turtle;

use turtle::{Turtle, Color};

fn main() {
    let mut turtle = Turtle::new();

    for i in 0..36 {
        let base_color: Color = if i % 2 == 0 {
            "red".into()
        } else {
            "white".into()
        };
        turtle.set_fill_color(base_color.with_alpha(1.0 - i as f64 / 54.0));
        turtle.begin_fill();
        square(&mut turtle);
        turtle.end_fill();
        turtle.right(10.0);
    }
}

fn square(turtle: &mut Turtle) {
    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::DynamicState;
use command_buffer::pool::CommandPool;
use command_buffer::states_manager::StatesManager;
use command_buffer::submit::Submit;
use command_buffer::submit::SubmitInfo;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use descriptor::PipelineLayout;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
use device::Device;
use device::Queue;
use framebuffer::traits::TrackedFramebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::GraphicsPipeline;
use pipeline::vertex::Source;
use sync::Fence;
use vk;

pub use self::empty::PrimaryCb;
pub use self::empty::PrimaryCbBuilder;

pub mod dispatch;
pub mod draw;
pub mod empty;
pub mod execute;
pub mod fill_buffer;
pub mod render_pass;
pub mod update_buffer;

/// A list of commands that can be turned into a command buffer.
pub unsafe trait CommandsListBase {
    /// Adds a command that writes the content of a buffer.
    ///
    /// After this command is executed, the content of `buffer` will become `data`.
    #[inline]
    fn update_buffer<'a, B, D: ?Sized>(self, buffer: B, data: &'a D)
                                       -> update_buffer::UpdateCommand<'a, Self, B, D>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer, D: Copy + 'static
    {
        update_buffer::UpdateCommand::new(self, buffer, data)
    }

    /// Adds a command that writes the content of a buffer.
    #[inline]
    fn fill_buffer<B>(self, buffer: B, data: u32) -> fill_buffer::FillCommand<Self, B>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer
    {
        fill_buffer::FillCommand::new(self, buffer, data)
    }

    /// Adds a command that executes a secondary command buffer.
    ///
    /// When you create a command buffer, you have the possibility to create either a primary
    /// command buffer or a secondary command buffer. Secondary command buffers can't be executed
    /// directly, but can be executed from a primary command buffer.
    ///
    /// A secondary command buffer can't execute another secondary command buffer. The only way
    /// you can use `execute` is to make a primary command buffer call a secondary command buffer.
    #[inline]
    fn execute<Cb>(self, command_buffer: Cb) -> execute::ExecuteCommand<Cb, Self>
        where Self: Sized, Cb: CommandsListOutput       /* FIXME: */
    {
        execute::ExecuteCommand::new(self, command_buffer)
    }

    /// Adds a command that executes a compute shader.
    ///
    /// The `dimensions` are the number of working groups to start. The GPU will execute the
    /// compute shader `dimensions[0] * dimensions[1] * dimensions[2]` times.
    ///
    /// The `pipeline` is the compute pipeline that will be executed, and the sets and push
    /// constants will be accessible to all the invocations.
    #[inline]
    fn dispatch<'a, Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
                               dimensions: [u32; 3], push_constants: &'a Pc)
                               -> dispatch::DispatchCommand<'a, Self, Pl, S, Pc>
        where Self: Sized + CommandsListBase + CommandsListPossibleOutsideRenderPass, Pl: PipelineLayout,
              S: TrackedDescriptorSetsCollection, Pc: 'a
    {
        dispatch::DispatchCommand::new(self, pipeline, sets, dimensions, push_constants)
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass on the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C>(self, framebuffer: F, secondary: bool, clear_values: C)
                               -> render_pass::BeginRenderPassCommand<Self, F::RenderPass, F>
        where Self: Sized + CommandsListPossibleOutsideRenderPass,
              F: TrackedFramebuffer, F::RenderPass: RenderPass + RenderPassClearValues<C>
    {
        render_pass::BeginRenderPassCommand::new(self, framebuffer, secondary, clear_values)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass(self, secondary: bool) -> render_pass::NextSubpassCommand<Self>
        where Self: Sized + CommandsListPossibleInsideRenderPass
    {
        render_pass::NextSubpassCommand::new(self, secondary)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass(self) -> render_pass::EndRenderPassCommand<Self>
        where Self: Sized + CommandsListPossibleInsideRenderPass
    {
        render_pass::EndRenderPassCommand::new(self)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<'a, Pv, Pl, Prp, S, Pc, V>(self, pipeline: Arc<GraphicsPipeline<Pv, Pl, Prp>>,
                                       dynamic: &DynamicState, vertices: V, sets: S,
                                       push_constants: &'a Pc)
                                       -> draw::DrawCommand<'a, Self, Pv, Pl, Prp, S, Pc>
        where Self: Sized + CommandsListBase + CommandsListPossibleInsideRenderPass, Pl: PipelineLayout,
              S: TrackedDescriptorSetsCollection, Pc: 'a, Pv: Source<V>
    {
        draw::DrawCommand::regular(self, pipeline, dynamic, vertices, sets, push_constants)
    }

    /// Returns true if the command buffer can be built. This function should always return true,
    /// except when we're building a primary command buffer that is inside a render pass.
    fn buildable_state(&self) -> bool;

    /// Returns the number of commands in the commands list.
    ///
    /// Note that multiple actual commands may count for just 1.
    fn num_commands(&self) -> usize;

    /// Checks whether the command can be executed on the given queue family.
    // TODO: error type?
    fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()>;

    /// Extracts the object that contains the states of all the resources of the commands list.
    ///
    /// Panics if the states were already extracted.
    fn extract_states(&mut self) -> StatesManager;

    /// Returns true if the given compute pipeline is currently binded in the commands list.
    // TODO: better API?
    fn is_compute_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool;

    /// Returns true if the given graphics pipeline is currently binded in the commands list.
    // TODO: better API?
    fn is_graphics_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool;
}

pub unsafe trait CommandsList: CommandsListBase {
    type Pool: CommandPool;
    /// The type of the command buffer that will be generated.
    type Output: CommandsListOutput;

    /// Turns the commands list into a command buffer.
    ///
    /// This function accepts additional arguments that will customize the output:
    ///
    /// - `additional_elements` is a closure that must be called on the command buffer builder
    ///   after it has finished building and before `final_barrier` are added.
    /// - `barriers` is a list of pipeline barriers accompanied by a command number. The
    ///   pipeline barrier must happen after the given command number. Usually you want all the
    ///   the command numbers to be inferior to `num_commands`.
    /// - `final_barrier` is a pipeline barrier that must be added at the end of the
    ///   command buffer builder.
    ///
    /// This function doesn't check that `buildable_state` returns true.
    unsafe fn raw_build<I, F>(self, in_s: &mut StatesManager, out: &mut StatesManager,
                              additional_elements: F, barriers: I,
                              final_barrier: PipelineBarrierBuilder) -> Self::Output
        where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
              I: Iterator<Item = (usize, PipelineBarrierBuilder)>;

    /// Turns the commands list into a command buffer that can be submitted.
    // This function isn't inline because `raw_build` implementations usually are inline.
    fn build(mut self) -> CommandBuffer<Self::Output> where Self: Sized {
        assert!(self.buildable_state(), "Tried to build a command buffer still inside a \
                                         render pass");

        let mut states_in = self.extract_states();
        let mut states_out = StatesManager::new();

        let output = unsafe {
            self.raw_build(&mut states_in, &mut states_out, |_| {},
                           iter::empty(), PipelineBarrierBuilder::new())
        };

        CommandBuffer {
            states: states_out,
            commands: output,
        }
    }
}

/*pub unsafe trait AbstractCommandsList: CommandsListBase {
    /// Turns the commands list into a command buffer that can be submitted.
    fn abstract_build(self) -> CommandBuffer where Self: Sized;
}

unsafe impl<C> AbstractCommandsList for C where C: CommandsList {
    #[inline]
    fn abstract_build(self) -> CommandBuffer {
        Box::new(self.build())
    }
}*/

/// Extension trait for both `CommandsListBase` and `CommandsListOutput` that indicates that we're
/// possibly outside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be outside
/// of a render pass. If it is implemented, then we maybe are but that's not sure.
pub unsafe trait CommandsListPossibleOutsideRenderPass {
    /// Returns `true` if we're outside a render pass.
    fn is_outside_render_pass(&self) -> bool;
}

/// Extension trait for both `CommandsListBase` and `CommandsListOutput` that indicates that we're
/// possibly inside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be inside
/// a render pass. If it is implemented, then we maybe are but that's not sure.
// TODO: make all return values optional, since we're possibly not in a render pass
pub unsafe trait CommandsListPossibleInsideRenderPass {
    type RenderPass: RenderPass;

    /// Returns the number of the subpass we're in. The value is 0-indexed, so immediately after
    /// calling `begin_render_pass` the value will be `0`.
    ///
    /// The value should always be strictly inferior to the number of subpasses in the render pass.
    fn current_subpass_num(&self) -> u32;

    /// If true, only secondary command buffers can be added inside the subpass. If false, only
    /// inline draw commands can be added.
    fn secondary_subpass(&self) -> bool;

    /// Returns the description of the render pass we're in.
    // TODO: return a trait object instead?
    fn render_pass(&self) -> &Self::RenderPass;

    //fn current_subpass(&self) -> Subpass<&Self::RenderPass>;
}

pub unsafe trait CommandsListOutput<S = StatesManager> {
    /// Returns the inner object.
    // TODO: crappy API
    fn inner(&self) -> vk::CommandBuffer;

    /// Returns the device this object belongs to.
    fn device(&self) -> &Arc<Device>;

    unsafe fn on_submit(&self, states: &S, queue: &Arc<Queue>,
                        fence: &mut FnMut() -> Arc<Fence>) -> SubmitInfo;
}

pub struct CommandBuffer<C /* = Box<CommandsListOutput>*/> {
    states: StatesManager,
    commands: C,
}

unsafe impl<C> Submit for CommandBuffer<C> where C: CommandsListOutput {
    #[inline]
    fn inner(&self) -> vk::CommandBuffer {
        self.commands.inner()
    }

    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.commands.device()
    }

    #[inline]
    unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, mut fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        self.commands.on_submit(&self.states, queue, &mut fence)
    }
}
<commit_msg>Add AbstractCommandsList<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::DynamicState;
use command_buffer::pool::CommandPool;
use command_buffer::states_manager::StatesManager;
use command_buffer::submit::Submit;
use command_buffer::submit::SubmitInfo;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use descriptor::PipelineLayout;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
use device::Device;
use device::Queue;
use framebuffer::traits::TrackedFramebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::GraphicsPipeline;
use pipeline::vertex::Source;
use sync::Fence;
use vk;

pub use self::empty::PrimaryCb;
pub use self::empty::PrimaryCbBuilder;

pub mod dispatch;
pub mod draw;
pub mod empty;
pub mod execute;
pub mod fill_buffer;
pub mod render_pass;
pub mod update_buffer;

/// A list of commands that can be turned into a command buffer.
pub unsafe trait CommandsListBase {
    /// Adds a command that writes the content of a buffer.
    ///
    /// After this command is executed, the content of `buffer` will become `data`.
    #[inline]
    fn update_buffer<'a, B, D: ?Sized>(self, buffer: B, data: &'a D)
                                       -> update_buffer::UpdateCommand<'a, Self, B, D>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer, D: Copy + 'static
    {
        update_buffer::UpdateCommand::new(self, buffer, data)
    }

    /// Adds a command that writes the content of a buffer.
    #[inline]
    fn fill_buffer<B>(self, buffer: B, data: u32) -> fill_buffer::FillCommand<Self, B>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer
    {
        fill_buffer::FillCommand::new(self, buffer, data)
    }

    /// Adds a command that executes a secondary command buffer.
    ///
    /// When you create a command buffer, you have the possibility to create either a primary
    /// command buffer or a secondary command buffer. Secondary command buffers can't be executed
    /// directly, but can be executed from a primary command buffer.
    ///
    /// A secondary command buffer can't execute another secondary command buffer. The only way
    /// you can use `execute` is to make a primary command buffer call a secondary command buffer.
    #[inline]
    fn execute<Cb>(self, command_buffer: Cb) -> execute::ExecuteCommand<Cb, Self>
        where Self: Sized, Cb: CommandsListOutput       /* FIXME: */
    {
        execute::ExecuteCommand::new(self, command_buffer)
    }

    /// Adds a command that executes a compute shader.
    ///
    /// The `dimensions` are the number of working groups to start. The GPU will execute the
    /// compute shader `dimensions[0] * dimensions[1] * dimensions[2]` times.
    ///
    /// The `pipeline` is the compute pipeline that will be executed, and the sets and push
    /// constants will be accessible to all the invocations.
    #[inline]
    fn dispatch<'a, Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
                               dimensions: [u32; 3], push_constants: &'a Pc)
                               -> dispatch::DispatchCommand<'a, Self, Pl, S, Pc>
        where Self: Sized + CommandsListBase + CommandsListPossibleOutsideRenderPass, Pl: PipelineLayout,
              S: TrackedDescriptorSetsCollection, Pc: 'a
    {
        dispatch::DispatchCommand::new(self, pipeline, sets, dimensions, push_constants)
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass on the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C>(self, framebuffer: F, secondary: bool, clear_values: C)
                               -> render_pass::BeginRenderPassCommand<Self, F::RenderPass, F>
        where Self: Sized + CommandsListPossibleOutsideRenderPass,
              F: TrackedFramebuffer, F::RenderPass: RenderPass + RenderPassClearValues<C>
    {
        render_pass::BeginRenderPassCommand::new(self, framebuffer, secondary, clear_values)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass(self, secondary: bool) -> render_pass::NextSubpassCommand<Self>
        where Self: Sized + CommandsListPossibleInsideRenderPass
    {
        render_pass::NextSubpassCommand::new(self, secondary)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass(self) -> render_pass::EndRenderPassCommand<Self>
        where Self: Sized + CommandsListPossibleInsideRenderPass
    {
        render_pass::EndRenderPassCommand::new(self)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<'a, Pv, Pl, Prp, S, Pc, V>(self, pipeline: Arc<GraphicsPipeline<Pv, Pl, Prp>>,
                                       dynamic: &DynamicState, vertices: V, sets: S,
                                       push_constants: &'a Pc)
                                       -> draw::DrawCommand<'a, Self, Pv, Pl, Prp, S, Pc>
        where Self: Sized + CommandsListBase + CommandsListPossibleInsideRenderPass, Pl: PipelineLayout,
              S: TrackedDescriptorSetsCollection, Pc: 'a, Pv: Source<V>
    {
        draw::DrawCommand::regular(self, pipeline, dynamic, vertices, sets, push_constants)
    }

    /// Returns true if the command buffer can be built. This function should always return true,
    /// except when we're building a primary command buffer that is inside a render pass.
    fn buildable_state(&self) -> bool;

    /// Returns the number of commands in the commands list.
    ///
    /// Note that multiple actual commands may count for just 1.
    fn num_commands(&self) -> usize;

    /// Checks whether the command can be executed on the given queue family.
    // TODO: error type?
    fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()>;

    /// Extracts the object that contains the states of all the resources of the commands list.
    ///
    /// Panics if the states were already extracted.
    fn extract_states(&mut self) -> StatesManager;

    /// Returns true if the given compute pipeline is currently binded in the commands list.
    // TODO: better API?
    fn is_compute_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool;

    /// Returns true if the given graphics pipeline is currently binded in the commands list.
    // TODO: better API?
    fn is_graphics_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool;
}

pub unsafe trait CommandsList: CommandsListBase {
    type Pool: CommandPool;
    /// The type of the command buffer that will be generated.
    type Output: CommandsListOutput;

    /// Turns the commands list into a command buffer.
    ///
    /// This function accepts additional arguments that will customize the output:
    ///
    /// - `additional_elements` is a closure that must be called on the command buffer builder
    ///   after it has finished building and before `final_barrier` are added.
    /// - `barriers` is a list of pipeline barriers accompanied by a command number. The
    ///   pipeline barrier must happen after the given command number. Usually you want all the
    ///   the command numbers to be inferior to `num_commands`.
    /// - `final_barrier` is a pipeline barrier that must be added at the end of the
    ///   command buffer builder.
    ///
    /// This function doesn't check that `buildable_state` returns true.
    unsafe fn raw_build<I, F>(self, in_s: &mut StatesManager, out: &mut StatesManager,
                              additional_elements: F, barriers: I,
                              final_barrier: PipelineBarrierBuilder) -> Self::Output
        where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
              I: Iterator<Item = (usize, PipelineBarrierBuilder)>;

    /// Turns the commands list into a command buffer that can be submitted.
    // This function isn't inline because `raw_build` implementations usually are inline.
    fn build(mut self) -> CommandBuffer<Self::Output> where Self: Sized {
        assert!(self.buildable_state(), "Tried to build a command buffer still inside a \
                                         render pass");

        let mut states_in = self.extract_states();
        let mut states_out = StatesManager::new();

        let output = unsafe {
            self.raw_build(&mut states_in, &mut states_out, |_| {},
                           iter::empty(), PipelineBarrierBuilder::new())
        };

        CommandBuffer {
            states: states_out,
            commands: output,
        }
    }
}

pub unsafe trait AbstractCommandsList: CommandsListBase {
    /// Turns the commands list into a command buffer that can be submitted.
    fn abstract_build(self) -> CommandBuffer where Self: Sized;
}

unsafe impl<C> AbstractCommandsList for C
    where C: CommandsList, <C as CommandsList>::Output: 'static
{
    #[inline]
    fn abstract_build(self) -> CommandBuffer {
        let tmp = self.build();

        CommandBuffer {
            states: tmp.states,
            commands: Box::new(tmp.commands) as Box<_>,
        }
    }
}

/// Extension trait for both `CommandsListBase` and `CommandsListOutput` that indicates that we're
/// possibly outside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be outside
/// of a render pass. If it is implemented, then we maybe are but that's not sure.
pub unsafe trait CommandsListPossibleOutsideRenderPass {
    /// Returns `true` if we're outside a render pass.
    fn is_outside_render_pass(&self) -> bool;
}

/// Extension trait for both `CommandsListBase` and `CommandsListOutput` that indicates that we're
/// possibly inside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be inside
/// a render pass. If it is implemented, then we maybe are but that's not sure.
// TODO: make all return values optional, since we're possibly not in a render pass
pub unsafe trait CommandsListPossibleInsideRenderPass {
    type RenderPass: RenderPass;

    /// Returns the number of the subpass we're in. The value is 0-indexed, so immediately after
    /// calling `begin_render_pass` the value will be `0`.
    ///
    /// The value should always be strictly inferior to the number of subpasses in the render pass.
    fn current_subpass_num(&self) -> u32;

    /// If true, only secondary command buffers can be added inside the subpass. If false, only
    /// inline draw commands can be added.
    fn secondary_subpass(&self) -> bool;

    /// Returns the description of the render pass we're in.
    // TODO: return a trait object instead?
    fn render_pass(&self) -> &Self::RenderPass;

    //fn current_subpass(&self) -> Subpass<&Self::RenderPass>;
}

pub unsafe trait CommandsListOutput<S = StatesManager> {
    /// Returns the inner object.
    // TODO: crappy API
    fn inner(&self) -> vk::CommandBuffer;

    /// Returns the device this object belongs to.
    fn device(&self) -> &Arc<Device>;

    unsafe fn on_submit(&self, states: &S, queue: &Arc<Queue>,
                        fence: &mut FnMut() -> Arc<Fence>) -> SubmitInfo;
}

pub struct CommandBuffer<C = Box<CommandsListOutput>> {
    states: StatesManager,
    commands: C,
}

unsafe impl<C> Submit for CommandBuffer<C> where C: CommandsListOutput {
    #[inline]
    fn inner(&self) -> vk::CommandBuffer {
        self.commands.inner()
    }

    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.commands.device()
    }

    #[inline]
    unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, mut fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        self.commands.on_submit(&self.states, queue, &mut fence)
    }
}
<|endoftext|>


<commit_before>use lsp_types::{SemanticTokenType, SemanticTokens, SemanticTokensLegend};

pub fn legend() -> SemanticTokensLegend {
    SemanticTokensLegend {
        token_types: vec![
            SemanticTokenType::COMMENT,        // 0
            SemanticTokenType::KEYWORD,        // 1
            SemanticTokenType::NAMESPACE,      // 2
            SemanticTokenType::TYPE,           // 3
            SemanticTokenType::TYPE_PARAMETER, // 4
            SemanticTokenType::ENUM_MEMBER,    // 5
            SemanticTokenType::STRING,         // 6
            SemanticTokenType::NUMBER,         // 7
            SemanticTokenType::MACRO,          // 8
        ],
        token_modifiers: vec![
            // TODO
        ],
    }
}

#[derive(Debug, Clone, Copy)]
enum TokenType {
    // Keep these in sync with indices of `token_types` above!
    Comment = 0,
    Keyword = 1,
    Namespace = 2,
    Type = 3,
    TypeVariable = 4,
    Constructor = 5,
    String = 6,
    Number = 7,
    Special = 8,
}

pub fn get_tokens(tree: &tree_sitter::Tree, source: &str) -> SemanticTokens {
    let mut tokens_builder = TokensBuilder::new();
    tokens_builder.build(tree, source.as_bytes());
    SemanticTokens {
        result_id: None,
        data: tokens_builder.into_tokens(),
    }
}

struct TokensBuilder(Vec<Node>);

#[derive(Debug)]
struct Node {
    start_line: usize,
    start_col: usize,
    token_type: TokenType,
    length: usize,
}

impl TokensBuilder {
    fn new() -> Self {
        Self(Vec::new())
    }

    fn push_node(&mut self, node: tree_sitter::Node, token_type: TokenType) {
        let tree_sitter::Point { row, column } = node.start_position();
        let length = node.byte_range().len();
        self.0.push(Node {
            start_line: row,
            start_col: column,
            length,
            token_type,
        })
    }

    fn into_tokens(mut self) -> Vec<lsp_types::SemanticToken> {
        let mut tokens = Vec::new();
        self.0.sort_by_key(|node| (node.start_line, node.start_col));
        let mut current_line = 0;
        let mut current_col = 0;
        for node in self.0 {
            let delta_line: u32 = (node.start_line - current_line).try_into().unwrap();
            let delta_start: u32 = if delta_line > 0 {
                node.start_col.try_into().unwrap()
            } else {
                (node.start_col - current_col).try_into().unwrap()
            };
            tokens.push(lsp_types::SemanticToken {
                delta_line,
                delta_start,
                token_type: node.token_type as u32,
                token_modifiers_bitset: 0,
                length: node.length as u32,
            });
            current_line = node.start_line;
            current_col = node.start_col;
        }
        tokens
    }

    fn build(&mut self, tree: &tree_sitter::Tree, source: &[u8]) {
        // NOTE: could just expose the highlights.scm in the tree-sitter-ditto
        // crate but relying on those indices feels brittle/wrong...
        static QUERY: &str = r#"
            ; 0
            (comment) @comment

            ; 1
            [
              "if"
              "then"
              "else"
              "module"
              "exports"
              "import"
              "as"
              "type"
              "foreign"
            ] @keyword

            ; 2, 3, 4
            (module_name) @namespace
            (module_import_alias) @namespace
            (qualifier) @namespace

            ; 5, 6, 7, 8
            (exposing_type_name) @type
            (type_declaration_name) @type
            (type_constructor) @type
            (type_function ("->" @type))

            ; 9, 10
            (type_variable) @type_variable
            (type_declaration_variable) @type_variable

            ; 11, 12
            (type_declaration_constructor_name) @constructor
            (expression_constructor_proper_name) @constructor

            ; 13
            (expression_string) @string

            ; 14, 15
            (expression_int) @number
            (expression_float) @number

            ; 16, 17
            (expression_true) @boolean
            (expression_false) @boolean

            ; 18
            (expression_unit) @builtin

            ; 19
            ("..") @special

        "#;
        let mut query_cursor = tree_sitter::QueryCursor::new();
        let query = tree_sitter::Query::new(tree_sitter_ditto::language(), QUERY).unwrap();
        let matches = query_cursor.matches(&query, tree.root_node(), source);
        for query_match in matches {
            let token_type = match query_match.pattern_index {
                0 => Some(TokenType::Comment),
                1 => Some(TokenType::Keyword),
                2 | 3 | 4 => Some(TokenType::Namespace),
                5 | 6 | 7 | 8 => Some(TokenType::Type),
                9 | 10 => Some(TokenType::TypeVariable),
                11 | 12 => Some(TokenType::Constructor),
                13 => Some(TokenType::String),
                14 | 15 => Some(TokenType::Number),
                // no boolean token type?
                // https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#standard-token-types-and-modifiers
                //
                // Might be worth "contributing" one?
                // https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#custom-token-types-and-modifiers
                16 | 17 | 18 => Some(TokenType::Keyword),
                19 => Some(TokenType::Special),
                _ => None,
            };
            if let Some(token_type) = token_type {
                for capture in query_match.captures {
                    self.push_node(capture.node, token_type)
                }
            }
        }
    }
}
<commit_msg>Add `match` and `with` keywords to lsp semantic highlighting<commit_after>use lsp_types::{SemanticTokenType, SemanticTokens, SemanticTokensLegend};

pub fn legend() -> SemanticTokensLegend {
    SemanticTokensLegend {
        token_types: vec![
            SemanticTokenType::COMMENT,        // 0
            SemanticTokenType::KEYWORD,        // 1
            SemanticTokenType::NAMESPACE,      // 2
            SemanticTokenType::TYPE,           // 3
            SemanticTokenType::TYPE_PARAMETER, // 4
            SemanticTokenType::ENUM_MEMBER,    // 5
            SemanticTokenType::STRING,         // 6
            SemanticTokenType::NUMBER,         // 7
            SemanticTokenType::MACRO,          // 8
        ],
        token_modifiers: vec![
            // TODO
        ],
    }
}

#[derive(Debug, Clone, Copy)]
enum TokenType {
    // Keep these in sync with indices of `token_types` above!
    Comment = 0,
    Keyword = 1,
    Namespace = 2,
    Type = 3,
    TypeVariable = 4,
    Constructor = 5,
    String = 6,
    Number = 7,
    Special = 8,
}

pub fn get_tokens(tree: &tree_sitter::Tree, source: &str) -> SemanticTokens {
    let mut tokens_builder = TokensBuilder::new();
    tokens_builder.build(tree, source.as_bytes());
    SemanticTokens {
        result_id: None,
        data: tokens_builder.into_tokens(),
    }
}

struct TokensBuilder(Vec<Node>);

#[derive(Debug)]
struct Node {
    start_line: usize,
    start_col: usize,
    token_type: TokenType,
    length: usize,
}

impl TokensBuilder {
    fn new() -> Self {
        Self(Vec::new())
    }

    fn push_node(&mut self, node: tree_sitter::Node, token_type: TokenType) {
        let tree_sitter::Point { row, column } = node.start_position();
        let length = node.byte_range().len();
        self.0.push(Node {
            start_line: row,
            start_col: column,
            length,
            token_type,
        })
    }

    fn into_tokens(mut self) -> Vec<lsp_types::SemanticToken> {
        let mut tokens = Vec::new();
        self.0.sort_by_key(|node| (node.start_line, node.start_col));
        let mut current_line = 0;
        let mut current_col = 0;
        for node in self.0 {
            let delta_line: u32 = (node.start_line - current_line).try_into().unwrap();
            let delta_start: u32 = if delta_line > 0 {
                node.start_col.try_into().unwrap()
            } else {
                (node.start_col - current_col).try_into().unwrap()
            };
            tokens.push(lsp_types::SemanticToken {
                delta_line,
                delta_start,
                token_type: node.token_type as u32,
                token_modifiers_bitset: 0,
                length: node.length as u32,
            });
            current_line = node.start_line;
            current_col = node.start_col;
        }
        tokens
    }

    fn build(&mut self, tree: &tree_sitter::Tree, source: &[u8]) {
        // NOTE: could just expose the highlights.scm in the tree-sitter-ditto
        // crate but relying on those indices feels brittle/wrong...
        static QUERY: &str = r#"
            ; 0
            (comment) @comment

            ; 1
            [
              "if"
              "then"
              "else"
              "module"
              "exports"
              "import"
              "as"
              "type"
              "foreign"
              "match"
              "with"
            ] @keyword

            ; 2, 3, 4
            (module_name) @namespace
            (module_import_alias) @namespace
            (qualifier) @namespace

            ; 5, 6, 7, 8
            (exposing_type_name) @type
            (type_declaration_name) @type
            (type_constructor) @type
            (type_function ("->" @type))

            ; 9, 10
            (type_variable) @type_variable
            (type_declaration_variable) @type_variable

            ; 11, 12
            (type_declaration_constructor_name) @constructor
            (expression_constructor_proper_name) @constructor

            ; 13
            (expression_string) @string

            ; 14, 15
            (expression_int) @number
            (expression_float) @number

            ; 16, 17
            (expression_true) @boolean
            (expression_false) @boolean

            ; 18
            (expression_unit) @builtin

            ; 19
            ("..") @special

        "#;
        let mut query_cursor = tree_sitter::QueryCursor::new();
        let query = tree_sitter::Query::new(tree_sitter_ditto::language(), QUERY).unwrap();
        let matches = query_cursor.matches(&query, tree.root_node(), source);
        for query_match in matches {
            let token_type = match query_match.pattern_index {
                0 => Some(TokenType::Comment),
                1 => Some(TokenType::Keyword),
                2 | 3 | 4 => Some(TokenType::Namespace),
                5 | 6 | 7 | 8 => Some(TokenType::Type),
                9 | 10 => Some(TokenType::TypeVariable),
                11 | 12 => Some(TokenType::Constructor),
                13 => Some(TokenType::String),
                14 | 15 => Some(TokenType::Number),
                // no boolean token type?
                // https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#standard-token-types-and-modifiers
                //
                // Might be worth "contributing" one?
                // https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#custom-token-types-and-modifiers
                16 | 17 | 18 => Some(TokenType::Keyword),
                19 => Some(TokenType::Special),
                _ => None,
            };
            if let Some(token_type) = token_type {
                for capture in query_match.captures {
                    self.push_node(capture.node, token_type)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use util::units::{Point, Size};

pub struct Rectangle {
    location: Point,
    size: Size,
}

impl Rectangle {

    pub fn new(location: Point, size: Size) -> Rectangle {
        Rectangle { location: location, size: size }
    }

    pub fn move_dir(&self, location: Point) -> Rectangle {
        Rectangle { location: self.location + location, size: self.size }
    }

    pub fn resize(&self, size: Size) -> Rectangle {
        Rectangle { location: self.location, size: self.size + size }
    }

    pub fn location(&self) -> Point {
        return self.location;
    }

    pub fn width(&self) -> i32 {
        return self.size.x;
    }

    pub fn height(&self) -> i32 {
        return self.size.y;
    }

}
<commit_msg>Allow Rectangle to return its own size as well as width/height<commit_after>use util::units::{Point, Size};

pub struct Rectangle {
    location: Point,
    size: Size,
}

impl Rectangle {

    pub fn new(location: Point, size: Size) -> Rectangle {
        Rectangle { location: location, size: size }
    }

    pub fn move_dir(&self, location: Point) -> Rectangle {
        Rectangle { location: self.location + location, size: self.size }
    }

    pub fn resize(&self, size: Size) -> Rectangle {
        Rectangle { location: self.location, size: self.size + size }
    }

    pub fn location(&self) -> Point {
        return self.location;
    }

    pub fn size(&self) -> Size {
        return self.size;
    }

    pub fn width(&self) -> i32 {
        return self.size.x;
    }

    pub fn height(&self) -> i32 {
        return self.size.y;
    }

}
<|endoftext|>


<commit_before>extern crate chattium_oxide_lib as cho;  // Chang
extern crate rand;

use rand::Rng;
use std::net::Ipv4Addr;

fn random_ip<Rand: Rng>(rng: &mut Rand) -> (Ipv4Addr, u16) {
	(Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), rng.gen())
}

fn random_name<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(10).collect()
}

fn random_text<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(100).collect()
}

#[cfg(test)]
mod user {
	use random_ip;
	use random_name;
	use rand;
	use cho::*;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			assert_eq!(user, user);
		}
	}

	#[test]
	fn equal_because_of_different_names_same_ips() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let ip = random_ip(&mut rng);
			let user_1 = ChatUser::get(random_name(&mut rng), ip);
			let user_2 = ChatUser::get(random_name(&mut rng), ip);
			assert_eq!(user_1, user_2);
		}
	}

	#[test]
	fn unequal_because_of_different_ips_same_names() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user_1 = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let user_2 = ChatUser::get(user_1.name.clone(), random_ip(&mut rng));
			assert!(user_1 != user_2);
		}
	}

	#[test]
	fn name_of_instance_from_get_is_equal_to_passed_name() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let name = random_name(&mut rng);
			let user = ChatUser::get(name.clone(), "0.0.0.0:0");
			assert_eq!(user.name, name);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
		let clone = user.clone();
		assert_eq!(user, clone);
		assert_eq!(user.name, clone.name);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("Full transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("IP-less transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let user_s = user.to_json_string().expect("Full serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("Full deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let user_s = user.to_json_string().expect("IP-less serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("IP-less deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatUser::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod message {
	use random_ip;
	use random_name;
	use random_text;
	use rand;
	use cho::*;
	use std::time::Duration;
	use std::thread::sleep;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
			assert_eq!(message, message);
		}
	}

	#[test]
	fn new_neq_new_time() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let text = random_text(&mut rng);
			let message_1 = ChatMessage::new(user.clone(), text.clone());
			sleep(Duration::new(0, 1));
			let message_2 = ChatMessage::new(user.clone(), text.clone());
			assert!(message_1.time_posted != message_2.time_posted);
		}
	}

	#[test]
	fn user_of_instance_from_new_is_equal_to_passed_user() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let sender = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let message = ChatMessage::new(sender.clone(), random_text(&mut rng));
			assert_eq!(message.sender, sender);
		}
	}

	#[test]
	fn content_of_instance_from_new_is_equal_to_passed_content() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let value = random_text(&mut rng);
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), value.clone());
			assert_eq!(message.value, value);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
		let clone = message.clone();
		assert_eq!(message, clone);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use random_text;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let trans = ChatMessage::from_json(message.to_json()).expect("Full transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let trans = ChatMessage::from_json(message.to_json()).expect("IP-less transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let message_s = message.to_json_string().expect("Full serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("Full deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let message_s = message.to_json_string().expect("IP-less serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("IP-less deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatMessage::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}
<commit_msg>Add time serialization tests<commit_after>extern crate chattium_oxide_lib as cho;  // Chang
extern crate rand;
extern crate time;

use time::Tm;
use rand::Rng;
use std::net::Ipv4Addr;

fn random_ip<Rand: Rng>(rng: &mut Rand) -> (Ipv4Addr, u16) {
	(Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), rng.gen())
}

fn random_name<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(10).collect()
}

fn random_text<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(100).collect()
}

fn random_time<Rand: Rng>(rng: &mut Rand) -> Tm {
	use time::{at_utc, Timespec};

	at_utc(Timespec::new(rng.gen_range(1420070400 /*1 Jan. 2015*/, 1893456000 /*1. Jan 2030*/), rng.gen_range(0, 1000000000)))
}

#[cfg(test)]
mod user {
	use random_ip;
	use random_name;
	use rand;
	use cho::*;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			assert_eq!(user, user);
		}
	}

	#[test]
	fn equal_because_of_different_names_same_ips() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let ip = random_ip(&mut rng);
			let user_1 = ChatUser::get(random_name(&mut rng), ip);
			let user_2 = ChatUser::get(random_name(&mut rng), ip);
			assert_eq!(user_1, user_2);
		}
	}

	#[test]
	fn unequal_because_of_different_ips_same_names() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user_1 = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let user_2 = ChatUser::get(user_1.name.clone(), random_ip(&mut rng));
			assert!(user_1 != user_2);
		}
	}

	#[test]
	fn name_of_instance_from_get_is_equal_to_passed_name() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let name = random_name(&mut rng);
			let user = ChatUser::get(name.clone(), "0.0.0.0:0");
			assert_eq!(user.name, name);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
		let clone = user.clone();
		assert_eq!(user, clone);
		assert_eq!(user.name, clone.name);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("Full transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("IP-less transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let user_s = user.to_json_string().expect("Full serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("Full deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let user_s = user.to_json_string().expect("IP-less serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("IP-less deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatUser::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod message {
	use random_ip;
	use random_name;
	use random_text;
	use rand;
	use cho::*;
	use std::time::Duration;
	use std::thread::sleep;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
			assert_eq!(message, message);
		}
	}

	#[test]
	fn new_neq_new_time() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let text = random_text(&mut rng);
			let message_1 = ChatMessage::new(user.clone(), text.clone());
			sleep(Duration::new(0, 1));
			let message_2 = ChatMessage::new(user.clone(), text.clone());
			assert!(message_1.time_posted != message_2.time_posted);
		}
	}

	#[test]
	fn user_of_instance_from_new_is_equal_to_passed_user() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let sender = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let message = ChatMessage::new(sender.clone(), random_text(&mut rng));
			assert_eq!(message.sender, sender);
		}
	}

	#[test]
	fn content_of_instance_from_new_is_equal_to_passed_content() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let value = random_text(&mut rng);
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), value.clone());
			assert_eq!(message.value, value);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
		let clone = message.clone();
		assert_eq!(message, clone);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use random_text;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let trans = ChatMessage::from_json(message.to_json()).expect("Full transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let trans = ChatMessage::from_json(message.to_json()).expect("IP-less transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let message_s = message.to_json_string().expect("Full serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("Full deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let message_s = message.to_json_string().expect("IP-less serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("IP-less deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatMessage::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod json_impl {
	use rand;
	use time::Tm;
	use random_time;
	use cho::json::*;

	#[test]
	fn time_transserializes_properly() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let time = random_time(&mut rng);
			let time_s = time.to_json_string().expect("Serialization to string via time::Tm");
			let trans = Tm::from_json_string(&time_s).expect("Deserialization from string via time::Tm");
			assert_eq!(time, trans);
		}
	}
}
<|endoftext|>