<commit_before>extern crate serial;
extern crate cpal;

#[macro_use]
extern crate vulkano;
extern crate winit;
extern crate vulkano_win;

use serial::prelude::*;

use winit::get_primary_monitor;
use winit::Event;

use std::sync::Arc;
use std::time::{Duration, Instant};

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

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

mod vs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/vert.glsl")}
}

mod fs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/frag.glsl")}
}

fn main() {
    println!("👗🌋 Vulkan Multitouch Frabric Visualizer | Version 0.1.0");

    // Port Init
    let mut fabric_port = serial::windows::COMPort::open("COM5").unwrap();
    let mut buf = vec![1u8; 16];
    fabric_port.configure(&SETTINGS);
    //fabric_port.set_timeout(Duration::from_secs(1));

    // Vulkan Instance
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
    };

    // Physical Device
    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
        .next()
        .expect("No vulkan device is available.");

    // OS Window
    let window = winit::WindowBuilder::new()
        .with_fullscreen(get_primary_monitor())
        .build_vk_surface(&instance)
        .unwrap();

    // Graphics Queue Supported
    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.");

    // Logical Device, Queues
    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")
    };

    // Device Queue
    let queue = queues.next().unwrap();

    // Swapchain, Swapchain Images
    let (swapchain, images) = {

        let caps = window.surface()
            .get_capabilities(&physical)
            .expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 720]);

        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(),
                       caps.min_image_count,
                       format,
                       dimensions,
                       1,
                       &caps.supported_usage_flags,
                       &queue,
                       SurfaceTransform::Identity,
                       alpha,
                       present,
                       true,
                       None)
                .expect("failed to create swapchain")
    };

    // VBO and IBO
    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex {
            position: [f32; 2],
            uv: [f32; 2],
        }
        impl_vertex!(Vertex, position, uv);

        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [Vertex {
                                            position: [1.0, -1.0],
                                            uv: [1.0, 0.0],
                                        },
                                        Vertex {
                                            position: [-1.0, -1.0],
                                            uv: [0.0, 0.0],
                                        },
                                        Vertex {
                                            position: [1.0, 1.0],
                                            uv: [1.0, 1.0],
                                        },
                                        Vertex {
                                            position: [-1.0, 1.0],
                                            uv: [0.0, 1.0],
                                        }]
                                               .iter()
                                               .cloned())
                .expect("failed to create VBO")
    };

    let index_buffer = {
        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [0u32, 1, 2, 1, 2, 3]
                                           .iter()
                                           .cloned())
                .expect("failed to create IBO")
    };

    // Descriptor Pool, Descriptor Set, Pipeline Layout, Uniforms
    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    let uniform_buffer = {
        CpuAccessibleBuffer::<fs::ty::Block>::from_data(&device,
                                                        &BufferUsage::all(),
                                                        Some(queue.family()),
                                                        fs::ty::Block {
                                                            mouse: [-1., -1., -1., -1.],
                                                            resolution: [images[0].dimensions()
                                                                             [0] as
                                                                         f32,
                                                                         images[0].dimensions()
                                                                             [1] as
                                                                         f32],
                                                            time: 0.,
                                                            _padding1_: 0.,
                                                            fabric: [[0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.]],
                                                        })
                .expect("failed to create Uniform Buffer")
    };

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::fs::ty::Block>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();

    let set = pipeline_layout::set0::Set::new(&descriptor_pool,
                                              &pipeline_layout,
                                              &pipeline_layout::set0::Descriptors {
                                                   uniforms: &uniform_buffer,
                                               });

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

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

    // Render Pass
    mod render_pass {

        use vulkano::format::Format;

        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: Format,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {}
            }
        }
    }

    let render_pass =
        render_pass::CustomRenderPass::new(&device,
                                           &render_pass::Formats {
                                                // Use the format of the images and one sample.
                                                color: (images[0].format(), 1),
                                            })
                .unwrap();

    // Graphics Pipeline
    let pipeline = GraphicsPipeline::new(&device,
                                         GraphicsPipelineParams {
                                             vertex_input: SingleBufferDefinition::new(),

                                             vertex_shader: vs.main_entry_point(),

                                             input_assembly: InputAssembly::triangle_list(),

                                             tessellation: None,

                                             geometry_shader: None,

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

    let mut submissions: Vec<Arc<Submission>> = Vec::new();
    let mut mx: f32 = -1.0;
    let mut my: f32 = -1.0;
    let mut mleft: f32 = 0.0;
    let now = Instant::now();

    loop {

        submissions.retain(|s| s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        let command_buffer = PrimaryCommandBufferBuilder::new(&device, queue.family())
            .draw_inline(&render_pass,
                         &framebuffers[image_num],
                         render_pass::ClearValues { color: [0.0, 0.0, 0.0, 1.0] })
            .draw_indexed(&pipeline,
                          &vertex_buffer,
                          &index_buffer,
                          &DynamicState::none(),
                          &set,
                          &())
            .draw_end()
            .build();

        {
            use std::io::Read;

            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();
            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.time = now.elapsed().as_secs() as f32 +
                                  (now.elapsed().subsec_nanos() as f32 / 1000000000.0);
            buffer_content.mouse = [mx, my, mleft, 0.0];

            let fabric_com = fabric_port.read(&mut buf[..]);

            buffer_content.fabric =
                [[1. - buf[3] as f32,
                  1. - buf[7] as f32,
                  1. - buf[11] as f32,
                  1. - buf[15] as f32],
                 [1. - buf[2] as f32,
                  1. - buf[6] as f32,
                  1. - buf[10] as f32,
                  1. - buf[14] as f32],
                 [1. - buf[1] as f32, 1. - buf[5] as f32, 1. - buf[9] as f32, 1. - buf[13] as f32],
                 [1. - buf[0] as f32, 1. - buf[4] as f32, 1. - buf[8] as f32, 1. - buf[12] as f32]];
        }

        submissions.push(command_buffer::submit(&command_buffer, &queue).unwrap());

        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                Event::KeyboardInput(winit::ElementState::Released,
                                     _,
                                     Some(winit::VirtualKeyCode::Escape)) => {
                    println!("Closing visualizer!");
                    return;
                }
                Event::MouseInput(winit::ElementState::Pressed, winit::MouseButton::Left) => {
                    println!("Mouse Down");
                    mleft = 1.0;
                }
                Event::MouseInput(winit::ElementState::Released, winit::MouseButton::Left) => {
                    println!("Mouse Up");
                    mleft = 0.0;
                }
                Event::MouseMoved(x, y) => {
                    mx = x as f32;
                    my = y as f32;
                }
                Event::Closed => return,
                _ => (),
            }
        }
    }
}

<commit_msg>Moved read location<commit_after>extern crate serial;
extern crate cpal;

#[macro_use]
extern crate vulkano;
extern crate winit;
extern crate vulkano_win;

use serial::prelude::*;
use std::io::Read;

use winit::get_primary_monitor;
use winit::Event;

use std::sync::Arc;
use std::time::{Duration, Instant};

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

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

mod vs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/vert.glsl")}
}

mod fs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/frag.glsl")}
}

fn main() {
    println!("👗🌋 Vulkan Multitouch Frabric Visualizer | Version 0.1.0");

    // Port Init
    let mut fabric_port = serial::windows::COMPort::open("COM5").unwrap();
    let mut buf = vec![1u8; 16];
    fabric_port.configure(&SETTINGS);
    //fabric_port.set_timeout(Duration::from_secs(1));

    // Vulkan Instance
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
    };

    // Physical Device
    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
        .next()
        .expect("No vulkan device is available.");

    // OS Window
    let window = winit::WindowBuilder::new()
        .with_fullscreen(get_primary_monitor())
        .build_vk_surface(&instance)
        .unwrap();

    // Graphics Queue Supported
    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.");

    // Logical Device, Queues
    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")
    };

    // Device Queue
    let queue = queues.next().unwrap();

    // Swapchain, Swapchain Images
    let (swapchain, images) = {

        let caps = window.surface()
            .get_capabilities(&physical)
            .expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 720]);

        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(),
                       caps.min_image_count,
                       format,
                       dimensions,
                       1,
                       &caps.supported_usage_flags,
                       &queue,
                       SurfaceTransform::Identity,
                       alpha,
                       present,
                       true,
                       None)
                .expect("failed to create swapchain")
    };

    // VBO and IBO
    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex {
            position: [f32; 2],
            uv: [f32; 2],
        }
        impl_vertex!(Vertex, position, uv);

        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [Vertex {
                                            position: [1.0, -1.0],
                                            uv: [1.0, 0.0],
                                        },
                                        Vertex {
                                            position: [-1.0, -1.0],
                                            uv: [0.0, 0.0],
                                        },
                                        Vertex {
                                            position: [1.0, 1.0],
                                            uv: [1.0, 1.0],
                                        },
                                        Vertex {
                                            position: [-1.0, 1.0],
                                            uv: [0.0, 1.0],
                                        }]
                                               .iter()
                                               .cloned())
                .expect("failed to create VBO")
    };

    let index_buffer = {
        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [0u32, 1, 2, 1, 2, 3]
                                           .iter()
                                           .cloned())
                .expect("failed to create IBO")
    };

    // Descriptor Pool, Descriptor Set, Pipeline Layout, Uniforms
    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    let uniform_buffer = {
        CpuAccessibleBuffer::<fs::ty::Block>::from_data(&device,
                                                        &BufferUsage::all(),
                                                        Some(queue.family()),
                                                        fs::ty::Block {
                                                            mouse: [-1., -1., -1., -1.],
                                                            resolution: [images[0].dimensions()
                                                                             [0] as
                                                                         f32,
                                                                         images[0].dimensions()
                                                                             [1] as
                                                                         f32],
                                                            time: 0.,
                                                            _padding1_: 0.,
                                                            fabric: [[0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.]],
                                                        })
                .expect("failed to create Uniform Buffer")
    };

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::fs::ty::Block>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();

    let set = pipeline_layout::set0::Set::new(&descriptor_pool,
                                              &pipeline_layout,
                                              &pipeline_layout::set0::Descriptors {
                                                   uniforms: &uniform_buffer,
                                               });

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

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

    // Render Pass
    mod render_pass {

        use vulkano::format::Format;

        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: Format,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {}
            }
        }
    }

    let render_pass =
        render_pass::CustomRenderPass::new(&device,
                                           &render_pass::Formats {
                                                // Use the format of the images and one sample.
                                                color: (images[0].format(), 1),
                                            })
                .unwrap();

    // Graphics Pipeline
    let pipeline = GraphicsPipeline::new(&device,
                                         GraphicsPipelineParams {
                                             vertex_input: SingleBufferDefinition::new(),

                                             vertex_shader: vs.main_entry_point(),

                                             input_assembly: InputAssembly::triangle_list(),

                                             tessellation: None,

                                             geometry_shader: None,

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

    let mut submissions: Vec<Arc<Submission>> = Vec::new();
    let mut mx: f32 = -1.0;
    let mut my: f32 = -1.0;
    let mut mleft: f32 = 0.0;
    let now = Instant::now();

    loop {

        submissions.retain(|s| s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        let command_buffer = PrimaryCommandBufferBuilder::new(&device, queue.family())
            .draw_inline(&render_pass,
                         &framebuffers[image_num],
                         render_pass::ClearValues { color: [0.0, 0.0, 0.0, 1.0] })
            .draw_indexed(&pipeline,
                          &vertex_buffer,
                          &index_buffer,
                          &DynamicState::none(),
                          &set,
                          &())
            .draw_end()
            .build();

        {

            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();
            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.time = now.elapsed().as_secs() as f32 +
                                  (now.elapsed().subsec_nanos() as f32 / 1000000000.0);
            buffer_content.mouse = [mx, my, mleft, 0.0];

            buffer_content.fabric =
                [[1. - buf[3] as f32,
                  1. - buf[7] as f32,
                  1. - buf[11] as f32,
                  1. - buf[15] as f32],
                 [1. - buf[2] as f32,
                  1. - buf[6] as f32,
                  1. - buf[10] as f32,
                  1. - buf[14] as f32],
                 [1. - buf[1] as f32, 1. - buf[5] as f32, 1. - buf[9] as f32, 1. - buf[13] as f32],
                 [1. - buf[0] as f32, 1. - buf[4] as f32, 1. - buf[8] as f32, 1. - buf[12] as f32]];
        }

        submissions.push(command_buffer::submit(&command_buffer, &queue).unwrap());

        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                Event::KeyboardInput(winit::ElementState::Released,
                                     _,
                                     Some(winit::VirtualKeyCode::Escape)) => {
                    println!("Closing visualizer!");
                    return;
                }
                Event::MouseInput(winit::ElementState::Pressed, winit::MouseButton::Left) => {
                    println!("Mouse Down");
                    mleft = 1.0;
                }
                Event::MouseInput(winit::ElementState::Released, winit::MouseButton::Left) => {
                    println!("Mouse Up");
                    mleft = 0.0;
                }
                Event::MouseMoved(x, y) => {
                    mx = x as f32;
                    my = y as f32;
                }
                Event::Closed => return,
                _ => (),
            }
        }

        fabric_port.read(&mut buf[..]);
    }
}

<|endoftext|>


<commit_before>use gfx::{self, CommandBuffer, Device, Encoder, Factory, PipelineState, Resources};
use gfx::format::{DepthStencil, Rgba8};
use gfx::handle::{DepthStencilView, RenderTargetView};
use gfx::traits::FactoryExt;
use gfx_device_gl;
use gfx_window_glutin;
use glutin::{ContextError, Window};
use std::error::{self, Error};
use std::fmt;

use math::FMatrix4;
use super::mesh::MeshBuffer;
use super::pipeline::{self, Data, Meta, Transform, Vertex};

const CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

pub trait SwapBuffers {
    fn swap_buffers(&mut self) -> Result<(), RenderError>;
}

impl SwapBuffers for Window {
    fn swap_buffers(&mut self) -> Result<(), RenderError> {
        Window::swap_buffers(self).map_err(|error| {
            match error {
                ContextError::ContextLost => RenderError::ContextLost,
                _ => RenderError::Unknown,
            }
        })
    }
}

pub struct Context<W, R, F, B, D>
    where W: SwapBuffers,
          R: Resources,
          F: Factory<R>,
          B: CommandBuffer<R>,
          D: Device<Resources = R, CommandBuffer = B>
{
    pub window: W,
    factory: F,
    device: D,
    encoder: Encoder<R, B>,
    state: PipelineState<R, Meta>,
    data: Data<R>,
}

impl Context<Window,
             gfx_device_gl::Resources,
             gfx_device_gl::Factory,
             gfx_device_gl::CommandBuffer,
             gfx_device_gl::Device> {
    pub fn from_glutin_window(window: Window) -> Self {
        let (device, mut factory, color, depth) = gfx_window_glutin::init_existing(&window);
        let encoder = factory.create_command_buffer().into();
        Context::new(window, factory, device, encoder, color, depth)
    }
}

impl<W, R, F, B, D> Context<W, R, F, B, D>
    where W: SwapBuffers,
          R: Resources,
          F: Factory<R>,
          B: CommandBuffer<R>,
          D: Device<Resources = R, CommandBuffer = B>
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn new(window: W,
           mut factory: F,
           device: D,
           encoder: Encoder<R, B>,
           color: RenderTargetView<R, Rgba8>,
           depth: DepthStencilView<R, DepthStencil>)
           -> Self {
        let state = factory.create_pipeline_simple(include_bytes!("../shader/cube.v.glsl"),
                                                   include_bytes!("../shader/cube.f.glsl"),
                                                   pipeline::new())
            .unwrap();
        let data = Data {
            // Using an empty slice here causes an error.
            buffer: factory.create_vertex_buffer(&[Vertex::default()]),
            transform: factory.create_constant_buffer(1),
            camera: [[0.0; 4]; 4],
            model: [[0.0; 4]; 4],
            color: color,
            depth: depth,
        };
        Context {
            window: window,
            factory: factory,
            device: device,
            encoder: encoder,
            state: state,
            data: data,
        }
    }

    pub fn set_transform(&mut self,
                         camera: &FMatrix4,
                         model: &FMatrix4)
                         -> Result<(), RenderError> {
        let transform = Transform::new(camera, model);
        self.data.camera = transform.camera;
        self.data.model = transform.model;
        self.encoder.update_buffer(&self.data.transform, &[transform], 0).map_err(|_| {
            // TODO: Coerce and expose the `UpdateError`.
            RenderError::Unknown
        })
    }

    pub fn draw_mesh_buffer(&mut self, buffer: &MeshBuffer) {
        let (buffer, slice) = self.factory
            .create_vertex_buffer_with_slice(buffer.vertices(), buffer.indices());
        self.data.buffer = buffer;
        self.encoder.draw(&slice, &self.state, &self.data);
    }

    pub fn clear(&mut self) {
        self.encoder.clear(&self.data.color, CLEAR_COLOR);
        self.encoder.clear_depth(&self.data.depth, 1.0);
    }

    pub fn flush(&mut self) -> Result<(), RenderError> {
        self.encoder.flush(&mut self.device);
        self.window.swap_buffers().and_then(|_| {
            self.device.cleanup();
            Ok(())
        })
    }
}

#[derive(Debug)]
pub enum RenderError {
    ContextLost,
    Unknown,
}

impl fmt::Display for RenderError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for RenderError {
    fn description(&self) -> &str {
        match *self {
            RenderError::ContextLost => "rendering context lost",
            _ => "unknown rendering error",
        }
    }
}
<commit_msg>Remove unneeded import.<commit_after>use gfx::{CommandBuffer, Device, Encoder, Factory, PipelineState, Resources};
use gfx::format::{DepthStencil, Rgba8};
use gfx::handle::{DepthStencilView, RenderTargetView};
use gfx::traits::FactoryExt;
use gfx_device_gl;
use gfx_window_glutin;
use glutin::{ContextError, Window};
use std::error::{self, Error};
use std::fmt;

use math::FMatrix4;
use super::mesh::MeshBuffer;
use super::pipeline::{self, Data, Meta, Transform, Vertex};

const CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

pub trait SwapBuffers {
    fn swap_buffers(&mut self) -> Result<(), RenderError>;
}

impl SwapBuffers for Window {
    fn swap_buffers(&mut self) -> Result<(), RenderError> {
        Window::swap_buffers(self).map_err(|error| {
            match error {
                ContextError::ContextLost => RenderError::ContextLost,
                _ => RenderError::Unknown,
            }
        })
    }
}

pub struct Context<W, R, F, B, D>
    where W: SwapBuffers,
          R: Resources,
          F: Factory<R>,
          B: CommandBuffer<R>,
          D: Device<Resources = R, CommandBuffer = B>
{
    pub window: W,
    factory: F,
    device: D,
    encoder: Encoder<R, B>,
    state: PipelineState<R, Meta>,
    data: Data<R>,
}

impl Context<Window,
             gfx_device_gl::Resources,
             gfx_device_gl::Factory,
             gfx_device_gl::CommandBuffer,
             gfx_device_gl::Device> {
    pub fn from_glutin_window(window: Window) -> Self {
        let (device, mut factory, color, depth) = gfx_window_glutin::init_existing(&window);
        let encoder = factory.create_command_buffer().into();
        Context::new(window, factory, device, encoder, color, depth)
    }
}

impl<W, R, F, B, D> Context<W, R, F, B, D>
    where W: SwapBuffers,
          R: Resources,
          F: Factory<R>,
          B: CommandBuffer<R>,
          D: Device<Resources = R, CommandBuffer = B>
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn new(window: W,
           mut factory: F,
           device: D,
           encoder: Encoder<R, B>,
           color: RenderTargetView<R, Rgba8>,
           depth: DepthStencilView<R, DepthStencil>)
           -> Self {
        let state = factory.create_pipeline_simple(include_bytes!("../shader/cube.v.glsl"),
                                                   include_bytes!("../shader/cube.f.glsl"),
                                                   pipeline::new())
            .unwrap();
        let data = Data {
            // Using an empty slice here causes an error.
            buffer: factory.create_vertex_buffer(&[Vertex::default()]),
            transform: factory.create_constant_buffer(1),
            camera: [[0.0; 4]; 4],
            model: [[0.0; 4]; 4],
            color: color,
            depth: depth,
        };
        Context {
            window: window,
            factory: factory,
            device: device,
            encoder: encoder,
            state: state,
            data: data,
        }
    }

    pub fn set_transform(&mut self,
                         camera: &FMatrix4,
                         model: &FMatrix4)
                         -> Result<(), RenderError> {
        let transform = Transform::new(camera, model);
        self.data.camera = transform.camera;
        self.data.model = transform.model;
        self.encoder.update_buffer(&self.data.transform, &[transform], 0).map_err(|_| {
            // TODO: Coerce and expose the `UpdateError`.
            RenderError::Unknown
        })
    }

    pub fn draw_mesh_buffer(&mut self, buffer: &MeshBuffer) {
        let (buffer, slice) = self.factory
            .create_vertex_buffer_with_slice(buffer.vertices(), buffer.indices());
        self.data.buffer = buffer;
        self.encoder.draw(&slice, &self.state, &self.data);
    }

    pub fn clear(&mut self) {
        self.encoder.clear(&self.data.color, CLEAR_COLOR);
        self.encoder.clear_depth(&self.data.depth, 1.0);
    }

    pub fn flush(&mut self) -> Result<(), RenderError> {
        self.encoder.flush(&mut self.device);
        self.window.swap_buffers().and_then(|_| {
            self.device.cleanup();
            Ok(())
        })
    }
}

#[derive(Debug)]
pub enum RenderError {
    ContextLost,
    Unknown,
}

impl fmt::Display for RenderError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for RenderError {
    fn description(&self) -> &str {
        match *self {
            RenderError::ContextLost => "rendering context lost",
            _ => "unknown rendering error",
        }
    }
}
<|endoftext|>


<commit_before>extern crate vulkano;
extern crate winit;

#[cfg(target_os = "macos")]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate metal_rs as metal;

use std::error;
use std::fmt;
use std::ptr;
use std::sync::Arc;

use vulkano::instance::Instance;
use vulkano::instance::InstanceExtensions;
use vulkano::swapchain::Surface;
use vulkano::swapchain::SurfaceCreationError;
use winit::{EventsLoop, WindowBuilder};
use winit::CreationError as WindowCreationError;

#[cfg(target_os = "macos")]
use objc::runtime::{YES};
#[cfg(target_os = "macos")]
use cocoa::base::id as cocoa_id;
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSWindow, NSView};
#[cfg(target_os = "macos")]
use metal::*;

use std::mem;

pub fn required_extensions() -> InstanceExtensions {
    let ideal = InstanceExtensions {
        khr_surface: true,
        khr_xlib_surface: true,
        khr_xcb_surface: true,
        khr_wayland_surface: true,
        khr_mir_surface: true,
        khr_android_surface: true,
        khr_win32_surface: true,
        mvk_ios_surface: true,
        mvk_macos_surface: true,
        ..InstanceExtensions::none()
    };

    match InstanceExtensions::supported_by_core() {
        Ok(supported) => supported.intersection(&ideal),
        Err(_) => InstanceExtensions::none()
    }
}

pub trait VkSurfaceBuild {
    fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError>;
}

impl VkSurfaceBuild for WindowBuilder {
    fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError> {
        let window = try!(self.build(events_loop));
        let surface = try!(unsafe { winit_to_surface(instance, &window) });

        Ok(Window {
            window: window,
            surface: surface,
        })
    }
}

pub struct Window {
    window: winit::Window,
    surface: Arc<Surface>,
}

impl Window {
    #[inline]
    pub fn window(&self) -> &winit::Window {
        &self.window
    }

    #[inline]
    pub fn surface(&self) -> &Arc<Surface> {
        &self.surface
    }
}

/// Error that can happen when creating a window.
#[derive(Debug)]
pub enum CreationError {
    /// Error when creating the surface.
    SurfaceCreationError(SurfaceCreationError),
    /// Error when creating the window.
    WindowCreationError(WindowCreationError),
}

impl error::Error for CreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CreationError::SurfaceCreationError(_) => "error while creating the surface",
            CreationError::WindowCreationError(_) => "error while creating the window",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CreationError::SurfaceCreationError(ref err) => Some(err),
            CreationError::WindowCreationError(ref err) => Some(err),
        }
    }
}

impl fmt::Display for CreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<SurfaceCreationError> for CreationError {
    #[inline]
    fn from(err: SurfaceCreationError) -> CreationError {
        CreationError::SurfaceCreationError(err)
    }
}

impl From<WindowCreationError> for CreationError {
    #[inline]
    fn from(err: WindowCreationError) -> CreationError {
        CreationError::WindowCreationError(err)
    }
}

#[cfg(target_os = "android")]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::android::WindowExt;
    Surface::from_anativewindow(instance, win.get_native_window())
}

#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::unix::WindowExt;
    match (win.get_wayland_display(), win.get_wayland_surface()) {
        (Some(display), Some(surface)) => Surface::from_wayland(instance, display, surface),
        _ => {
            // No wayland display found, check if we can use xlib.
            // If not, we use xcb.
            if instance.loaded_extensions().khr_xlib_surface {
                Surface::from_xlib(instance,
                                   win.get_xlib_display().unwrap(),
                                   win.get_xlib_window().unwrap() as _)
            } else {
                Surface::from_xcb(instance,
                                   win.get_xcb_connection().unwrap(),
                                   win.get_xlib_window().unwrap() as _)
            }
        }
    }
}

#[cfg(target_os = "windows")]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::windows::WindowExt;
    Surface::from_hwnd(instance,
                       ptr::null() as *const (), // FIXME
                       win.get_hwnd())
}

#[cfg(target_os = "macos")]
unsafe fn winit_to_surface(instance: Arc<Instance>, win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError>
{
    use winit::os::macos::WindowExt;

    unsafe {
        let wnd: cocoa_id = mem::transmute(win.get_nswindow());

        let layer = CAMetalLayer::new();

        layer.set_edge_antialiasing_mask(0);
        layer.set_presents_with_transaction(false);
        layer.remove_all_animations();

        let view = wnd.contentView();
        view.setWantsLayer(YES);
        view.setLayer(mem::transmute(layer.0));  // Bombs here with out of memory
    }

    Surface::from_macos_moltenvk(instance, win.get_nsview() as *const ())
}
<commit_msg>Fix unused imports<commit_after>extern crate vulkano;
extern crate winit;

#[cfg(target_os = "macos")]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate metal_rs as metal;

use std::error;
use std::fmt;
#[cfg(target_os = "windows")]
use std::ptr;
use std::sync::Arc;

use vulkano::instance::Instance;
use vulkano::instance::InstanceExtensions;
use vulkano::swapchain::Surface;
use vulkano::swapchain::SurfaceCreationError;
use winit::{EventsLoop, WindowBuilder};
use winit::CreationError as WindowCreationError;

#[cfg(target_os = "macos")]
use objc::runtime::{YES};
#[cfg(target_os = "macos")]
use cocoa::base::id as cocoa_id;
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSWindow, NSView};
#[cfg(target_os = "macos")]
use metal::*;

#[cfg(target_os = "macos")]
use std::mem;

pub fn required_extensions() -> InstanceExtensions {
    let ideal = InstanceExtensions {
        khr_surface: true,
        khr_xlib_surface: true,
        khr_xcb_surface: true,
        khr_wayland_surface: true,
        khr_mir_surface: true,
        khr_android_surface: true,
        khr_win32_surface: true,
        mvk_ios_surface: true,
        mvk_macos_surface: true,
        ..InstanceExtensions::none()
    };

    match InstanceExtensions::supported_by_core() {
        Ok(supported) => supported.intersection(&ideal),
        Err(_) => InstanceExtensions::none()
    }
}

pub trait VkSurfaceBuild {
    fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError>;
}

impl VkSurfaceBuild for WindowBuilder {
    fn build_vk_surface(self, events_loop: &EventsLoop, instance: Arc<Instance>) -> Result<Window, CreationError> {
        let window = try!(self.build(events_loop));
        let surface = try!(unsafe { winit_to_surface(instance, &window) });

        Ok(Window {
            window: window,
            surface: surface,
        })
    }
}

pub struct Window {
    window: winit::Window,
    surface: Arc<Surface>,
}

impl Window {
    #[inline]
    pub fn window(&self) -> &winit::Window {
        &self.window
    }

    #[inline]
    pub fn surface(&self) -> &Arc<Surface> {
        &self.surface
    }
}

/// Error that can happen when creating a window.
#[derive(Debug)]
pub enum CreationError {
    /// Error when creating the surface.
    SurfaceCreationError(SurfaceCreationError),
    /// Error when creating the window.
    WindowCreationError(WindowCreationError),
}

impl error::Error for CreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CreationError::SurfaceCreationError(_) => "error while creating the surface",
            CreationError::WindowCreationError(_) => "error while creating the window",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CreationError::SurfaceCreationError(ref err) => Some(err),
            CreationError::WindowCreationError(ref err) => Some(err),
        }
    }
}

impl fmt::Display for CreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<SurfaceCreationError> for CreationError {
    #[inline]
    fn from(err: SurfaceCreationError) -> CreationError {
        CreationError::SurfaceCreationError(err)
    }
}

impl From<WindowCreationError> for CreationError {
    #[inline]
    fn from(err: WindowCreationError) -> CreationError {
        CreationError::WindowCreationError(err)
    }
}

#[cfg(target_os = "android")]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::android::WindowExt;
    Surface::from_anativewindow(instance, win.get_native_window())
}

#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::unix::WindowExt;
    match (win.get_wayland_display(), win.get_wayland_surface()) {
        (Some(display), Some(surface)) => Surface::from_wayland(instance, display, surface),
        _ => {
            // No wayland display found, check if we can use xlib.
            // If not, we use xcb.
            if instance.loaded_extensions().khr_xlib_surface {
                Surface::from_xlib(instance,
                                   win.get_xlib_display().unwrap(),
                                   win.get_xlib_window().unwrap() as _)
            } else {
                Surface::from_xcb(instance,
                                   win.get_xcb_connection().unwrap(),
                                   win.get_xlib_window().unwrap() as _)
            }
        }
    }
}

#[cfg(target_os = "windows")]
unsafe fn winit_to_surface(instance: Arc<Instance>,
                           win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError> {
    use winit::os::windows::WindowExt;
    Surface::from_hwnd(instance,
                       ptr::null() as *const (), // FIXME
                       win.get_hwnd())
}

#[cfg(target_os = "macos")]
unsafe fn winit_to_surface(instance: Arc<Instance>, win: &winit::Window)
                           -> Result<Arc<Surface>, SurfaceCreationError>
{
    use winit::os::macos::WindowExt;

    unsafe {
        let wnd: cocoa_id = mem::transmute(win.get_nswindow());

        let layer = CAMetalLayer::new();

        layer.set_edge_antialiasing_mask(0);
        layer.set_presents_with_transaction(false);
        layer.remove_all_animations();

        let view = wnd.contentView();
        view.setWantsLayer(YES);
        view.setLayer(mem::transmute(layer.0));  // Bombs here with out of memory
    }

    Surface::from_macos_moltenvk(instance, win.get_nsview() as *const ())
}
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;
use ::NEWLINE;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conin, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let rx = Screen::spawn_input_thread(conin as usize);
        let initial_pos = Screen::get_cursor_pos(conout);
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = get_start_line(rows, visible_choices, initial_pos);
        let original_colors = Screen::get_original_colors(conout);
        let (column, _) = initial_pos;
        if column > 0 {
            Self::write_to(conout, NEWLINE);
        }
        for _ in 0..visible_choices {
            Self::write_to(conout, NEWLINE);
        }
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line + Self::get_buffer_offset(conout),
            original_console_mode: orig_mode,
            original_colors: original_colors,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        let start_line = self.start_line;
        self.move_cursor(start_line, col);
    }

    pub fn blank_screen(&mut self) {
        let blank_line = repeat(' ').take((self.width - 1) as usize).collect::<String>();
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        for _ in 0..self.visible_choices {
            self.write(&blank_line);
            self.write(NEWLINE);
        }
        self.write(&blank_line);
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        Self::write_to(self.conout, s);
    }

    fn write_to(conout: HANDLE, s: &str) {
        let mut chars_written: DWORD = 0;
        let chars_to_write = s.chars().count() as DWORD;
        win32!(WriteConsoleW(conout, Screen::to_wide_char(s), chars_to_write, &mut chars_written as LPDWORD, ptr::null_mut()));
    }

    fn to_wide_char(s: &str) -> PVOID {
        let mut ret = Vec::with_capacity(5001);
        unsafe {
            let buf = ret.as_mut_ptr();
            let _ = MultiByteToWideChar(CP_UTF8, 0, s.as_ptr() as *const i8, s.len() as i32, buf, 2500);
        }
        ret.as_ptr() as PVOID
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_cursor_pos(handle: HANDLE) -> (u16, u16) {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        let cursor_pos = buffer_info.dwCursorPosition;
        (cursor_pos.X as u16, cursor_pos.Y as u16)
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }

    fn get_buffer_offset(conout: HANDLE) -> u16 {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(conout, &mut buffer_info));
        buffer_info.srWindow.Top as u16
    }
}

fn get_start_line(rows: u16, visible_choices: u16, initial_pos: (u16, u16)) -> u16 {
    let bottom_most_line = rows - visible_choices - 1;
    let (initial_x, initial_y) = initial_pos;
    let line_under_cursor = if initial_x == 0 { initial_y } else { initial_y + 1 };
    if line_under_cursor + 1 + visible_choices > rows {
        bottom_most_line
    } else {
        line_under_cursor
    }
}

#[cfg(test)]
mod tests {
    use super::kernel32;
    use super::winapi::STD_OUTPUT_HANDLE;
    use super::{Screen, get_start_line};

    #[test]
    fn winsize_test() {
        // AppVeyor builds run without a console, making this test impossible.
        if option_env!("APPVEYOR").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let conout = unsafe { kernel32::GetStdHandle(STD_OUTPUT_HANDLE) };
        let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }

    #[test]
    fn start_line_test() {
        assert_eq!(5, get_start_line(100, 20, (0, 5)));
        assert_eq!(6, get_start_line(100, 20, (1, 5)));
        assert_eq!(79, get_start_line(100, 20, (0, 100)));
        assert_eq!(0, get_start_line(15, 14, ((0, 5))));
        assert_eq!(79, get_start_line(100, 20, (50, 100)));
    }
}
<commit_msg>Fix Windows rendering regression<commit_after>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;
use ::NEWLINE;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conin, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let rx = Screen::spawn_input_thread(conin as usize);
        let initial_pos = Screen::get_cursor_pos(conout);
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = get_start_line(rows, visible_choices, initial_pos);
        let original_colors = Screen::get_original_colors(conout);
        let (column, _) = initial_pos;
        if column > 0 {
            Self::write_to(conout, NEWLINE);
        }
        for _ in 0..visible_choices {
            Self::write_to(conout, NEWLINE);
        }
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line + Self::get_buffer_offset(conout),
            original_console_mode: orig_mode,
            original_colors: original_colors,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        let start_line = self.start_line;
        self.move_cursor(start_line, col);
    }

    pub fn blank_screen(&mut self) {
        let blank_line = repeat(' ').take((self.width - 1) as usize).collect::<String>();
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        for _ in 0..self.visible_choices {
            self.write(&blank_line);
            self.write(NEWLINE);
        }
        self.write(&blank_line);
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        Self::write_to(self.conout, s);
    }

    fn write_to(conout: HANDLE, s: &str) {
        let mut chars_written: DWORD = 0;
        let utf16 = s.encode_utf16().collect::<Vec<u16>>();
        let chars_to_write = utf16.len() as DWORD;
        win32!(WriteConsoleW(conout, utf16.as_ptr() as PVOID, chars_to_write, &mut chars_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_cursor_pos(handle: HANDLE) -> (u16, u16) {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        let cursor_pos = buffer_info.dwCursorPosition;
        (cursor_pos.X as u16, cursor_pos.Y as u16)
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }

    fn get_buffer_offset(conout: HANDLE) -> u16 {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(conout, &mut buffer_info));
        buffer_info.srWindow.Top as u16
    }
}

fn get_start_line(rows: u16, visible_choices: u16, initial_pos: (u16, u16)) -> u16 {
    let bottom_most_line = rows - visible_choices - 1;
    let (initial_x, initial_y) = initial_pos;
    let line_under_cursor = if initial_x == 0 { initial_y } else { initial_y + 1 };
    if line_under_cursor + 1 + visible_choices > rows {
        bottom_most_line
    } else {
        line_under_cursor
    }
}

#[cfg(test)]
mod tests {
    use super::kernel32;
    use super::winapi::STD_OUTPUT_HANDLE;
    use super::{Screen, get_start_line};

    #[test]
    fn winsize_test() {
        // AppVeyor builds run without a console, making this test impossible.
        if option_env!("APPVEYOR").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let conout = unsafe { kernel32::GetStdHandle(STD_OUTPUT_HANDLE) };
        let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }

    #[test]
    fn start_line_test() {
        assert_eq!(5, get_start_line(100, 20, (0, 5)));
        assert_eq!(6, get_start_line(100, 20, (1, 5)));
        assert_eq!(79, get_start_line(100, 20, (0, 100)));
        assert_eq!(0, get_start_line(15, 14, ((0, 5))));
        assert_eq!(79, get_start_line(100, 20, (50, 100)));
    }
}
<|endoftext|>


<commit_before>use ast;
use ast::visit::{self, Visitor};
use class::*;
use ctxt::{Context, Fct, FctId, FctKind, FctSrc};
use error::msg::Msg;
use lexer::position::Position;
use mem;
use semck;
use ty::BuiltinType;

pub fn check<'ast>(ctxt: &mut Context<'ast>) {
    let mut clsck = ClsDefCheck {
        ctxt: ctxt,
        ast: ctxt.ast,
        cls_id: None,
    };

    clsck.check();
}

struct ClsDefCheck<'x, 'ast: 'x> {
    ctxt: &'x mut Context<'ast>,
    ast: &'ast ast::Ast,
    cls_id: Option<ClassId>,
}

impl<'x, 'ast> ClsDefCheck<'x, 'ast> {
    fn check(&mut self) {
        self.visit_ast(self.ast);
    }

    fn cls(&self) -> &Class<'ast> {
        self.ctxt.cls_by_id(self.cls_id.unwrap())
    }

    fn cls_mut(&mut self) -> &mut Class<'ast> {
        self.ctxt.cls_by_id_mut(self.cls_id.unwrap())
    }
}

impl<'x, 'ast> Visitor<'ast> for ClsDefCheck<'x, 'ast> {
    fn visit_class(&mut self, c: &'ast ast::Class) {
        self.cls_id = Some(*self.ctxt.cls_defs.get(&c.id).unwrap());

        visit::walk_class(self, c);

        self.cls_id = None;
    }

    fn visit_prop(&mut self, p: &'ast ast::Prop) {
        let ty = semck::read_type(self.ctxt, &p.data_type);

        for prop in &self.cls().props {
            if prop.name == p.name {
                let name = self.ctxt.interner.str(p.name).to_string();
                report(self.ctxt, p.pos, Msg::ShadowProp(name));
            }
        }

        let mut class = self.cls_mut();

        let offset = if ty.size() > 0 {
            mem::align_i32(class.size, ty.size())
        } else {
            class.size
        };

        let prop = Prop {
            name: p.name,
            ty: ty,
            offset: offset,
        };

        class.size = offset + ty.size();
        class.props.push(prop);
    }

    fn visit_ctor(&mut self, f: &'ast ast::Function) {
        let clsid = self.cls_id.unwrap();

        let fct = Fct {
            id: FctId(0),
            name: f.name,
            params_types: Vec::new(),
            return_type: BuiltinType::Unit,
            owner_class: Some(clsid),
            ctor: true,
            initialized: false,
            kind: FctKind::Source(FctSrc::new(f)),
        };

        let fctid = self.ctxt.add_fct(fct);
        self.cls_mut().ctor = fctid;
    }

    fn visit_method(&mut self, f: &'ast ast::Function) {
        let fct = Fct {
            id: FctId(0),
            name: f.name,
            params_types: Vec::new(),
            return_type: BuiltinType::Unit,
            owner_class: Some(self.cls_id.unwrap()),
            ctor: false,
            initialized: false,
            kind: FctKind::Source(FctSrc::new(f)),
        };

        let fctid = self.ctxt.add_fct(fct);

        self.cls_mut().methods.push(fctid);
    }
}

fn report(ctxt: &Context, pos: Position, msg: Msg) {
    ctxt.diag.borrow_mut().report(pos, msg);
}

#[cfg(test)]
mod tests {
    use error::msg::Msg;
    use interner::Name;
    use mem;
    use semck::tests::*;

    fn class_size(code: &'static str) -> i32 {
        ok_with_test(code, |ctxt| {
            ctxt.classes[0].size
        })
    }

    #[test]
    fn test_class_size() {
        assert_eq!(mem::ptr_width(), class_size("class Foo"));
        assert_eq!(mem::ptr_width() + 4, class_size("class Foo(a: int)"));
        assert_eq!(2 * mem::ptr_width(), class_size("class Foo(a: Str)"));
    }

    #[test]
    fn test_class_definition() {
        ok("class Foo");
        ok("class Foo()");
        ok("class Foo(a: int)");
        ok("class Foo(a: int, b:int)");
        ok("class Foo(a: Foo)");
        ok("class Foo(a: Bar) class Bar");
        err("class Foo(a: Unknown)", pos(1, 14), Msg::UnknownType(Name(2)));
        err("class Foo(a: int, a: int)", pos(1, 19), Msg::ShadowProp("a".to_string()));
    }
}
<commit_msg>test fct and class with same name<commit_after>use ast;
use ast::visit::{self, Visitor};
use class::*;
use ctxt::{Context, Fct, FctId, FctKind, FctSrc};
use error::msg::Msg;
use lexer::position::Position;
use mem;
use semck;
use ty::BuiltinType;

pub fn check<'ast>(ctxt: &mut Context<'ast>) {
    let mut clsck = ClsDefCheck {
        ctxt: ctxt,
        ast: ctxt.ast,
        cls_id: None,
    };

    clsck.check();
}

struct ClsDefCheck<'x, 'ast: 'x> {
    ctxt: &'x mut Context<'ast>,
    ast: &'ast ast::Ast,
    cls_id: Option<ClassId>,
}

impl<'x, 'ast> ClsDefCheck<'x, 'ast> {
    fn check(&mut self) {
        self.visit_ast(self.ast);
    }

    fn cls(&self) -> &Class<'ast> {
        self.ctxt.cls_by_id(self.cls_id.unwrap())
    }

    fn cls_mut(&mut self) -> &mut Class<'ast> {
        self.ctxt.cls_by_id_mut(self.cls_id.unwrap())
    }
}

impl<'x, 'ast> Visitor<'ast> for ClsDefCheck<'x, 'ast> {
    fn visit_class(&mut self, c: &'ast ast::Class) {
        self.cls_id = Some(*self.ctxt.cls_defs.get(&c.id).unwrap());

        visit::walk_class(self, c);

        self.cls_id = None;
    }

    fn visit_prop(&mut self, p: &'ast ast::Prop) {
        let ty = semck::read_type(self.ctxt, &p.data_type);

        for prop in &self.cls().props {
            if prop.name == p.name {
                let name = self.ctxt.interner.str(p.name).to_string();
                report(self.ctxt, p.pos, Msg::ShadowProp(name));
            }
        }

        let mut class = self.cls_mut();

        let offset = if ty.size() > 0 {
            mem::align_i32(class.size, ty.size())
        } else {
            class.size
        };

        let prop = Prop {
            name: p.name,
            ty: ty,
            offset: offset,
        };

        class.size = offset + ty.size();
        class.props.push(prop);
    }

    fn visit_ctor(&mut self, f: &'ast ast::Function) {
        let clsid = self.cls_id.unwrap();

        let fct = Fct {
            id: FctId(0),
            name: f.name,
            params_types: Vec::new(),
            return_type: BuiltinType::Unit,
            owner_class: Some(clsid),
            ctor: true,
            initialized: false,
            kind: FctKind::Source(FctSrc::new(f)),
        };

        let fctid = self.ctxt.add_fct(fct);
        self.cls_mut().ctor = fctid;
    }

    fn visit_method(&mut self, f: &'ast ast::Function) {
        let fct = Fct {
            id: FctId(0),
            name: f.name,
            params_types: Vec::new(),
            return_type: BuiltinType::Unit,
            owner_class: Some(self.cls_id.unwrap()),
            ctor: false,
            initialized: false,
            kind: FctKind::Source(FctSrc::new(f)),
        };

        let fctid = self.ctxt.add_fct(fct);

        self.cls_mut().methods.push(fctid);
    }
}

fn report(ctxt: &Context, pos: Position, msg: Msg) {
    ctxt.diag.borrow_mut().report(pos, msg);
}

#[cfg(test)]
mod tests {
    use error::msg::Msg;
    use interner::Name;
    use mem;
    use semck::tests::*;

    fn class_size(code: &'static str) -> i32 {
        ok_with_test(code, |ctxt| {
            ctxt.classes[0].size
        })
    }

    #[test]
    fn test_class_size() {
        assert_eq!(mem::ptr_width(), class_size("class Foo"));
        assert_eq!(mem::ptr_width() + 4, class_size("class Foo(a: int)"));
        assert_eq!(2 * mem::ptr_width(), class_size("class Foo(a: Str)"));
    }

    #[test]
    fn test_multiple_definition() {
        err("class Foo class Foo", pos(1, 11), Msg::ShadowType("Foo".into()));
    }

    #[test]
    fn test_class_and_function() {
        err("fn Foo() {} class Foo", pos(1, 13), Msg::ShadowFunction("Foo".into()));
        err("class Foo fn Foo() {}", pos(1, 11), Msg::ShadowType("Foo".into()));
    }

    #[test]
    fn test_class_definition() {
        ok("class Foo");
        ok("class Foo()");
        ok("class Foo(a: int)");
        ok("class Foo(a: int, b:int)");
        ok("class Foo(a: Foo)");
        ok("class Foo(a: Bar) class Bar");
        err("class Foo(a: Unknown)", pos(1, 14), Msg::UnknownType(Name(2)));
        err("class Foo(a: int, a: int)", pos(1, 19), Msg::ShadowProp("a".to_string()));
    }
}
<|endoftext|>


<commit_before>use anyhow::Error;

static CATEGORIES_TOML: &str = include_str!("../boot/categories.toml");
diesel_migrations::embed_migrations!("./migrations");

#[derive(clap::Parser, Debug, Copy, Clone)]
#[command(
    name = "migrate",
    about = "Verify config, migrate the database, and other release tasks."
)]
pub struct Opts;

pub fn run(_opts: Opts) -> Result<(), Error> {
    let config = crate::config::DatabasePools::full_from_environment(
        &crate::config::Base::from_environment(),
    );

    // TODO: Refactor logic so that we can also check things from App::new() here.
    // If the app will panic due to bad configuration, it is better to error in the release phase
    // to avoid launching dynos that will fail.

    if config.are_all_read_only() {
        // TODO: Check `any_pending_migrations()` with a read-only connection and error if true.
        // It looks like this requires changes upstream to make this pub in `migration_macros`.

        println!("==> Skipping migrations and category sync (read-only mode)");

        // The service is undergoing maintenance or mitigating an outage.
        // Exit with success to ensure configuration changes can be made.
        // Heroku will not launch new dynos if the release phase fails.
        return Ok(());
    }

    // The primary is online, access directly via `DATABASE_URL`.
    let conn = crate::db::oneoff_connection_with_config(&config)?;

    println!("==> migrating the database");
    embedded_migrations::run_with_output(&conn, &mut std::io::stdout())?;

    println!("==> synchronizing crate categories");
    crate::boot::categories::sync_with_connection(CATEGORIES_TOML, &conn).unwrap();

    Ok(())
}
<commit_msg>admin::migrate: Use `tracing` macros instead of `println!()`<commit_after>use anyhow::Error;

static CATEGORIES_TOML: &str = include_str!("../boot/categories.toml");
diesel_migrations::embed_migrations!("./migrations");

#[derive(clap::Parser, Debug, Copy, Clone)]
#[command(
    name = "migrate",
    about = "Verify config, migrate the database, and other release tasks."
)]
pub struct Opts;

pub fn run(_opts: Opts) -> Result<(), Error> {
    let config = crate::config::DatabasePools::full_from_environment(
        &crate::config::Base::from_environment(),
    );

    // TODO: Refactor logic so that we can also check things from App::new() here.
    // If the app will panic due to bad configuration, it is better to error in the release phase
    // to avoid launching dynos that will fail.

    if config.are_all_read_only() {
        // TODO: Check `any_pending_migrations()` with a read-only connection and error if true.
        // It looks like this requires changes upstream to make this pub in `migration_macros`.

        warn!("Skipping migrations and category sync (read-only mode)");

        // The service is undergoing maintenance or mitigating an outage.
        // Exit with success to ensure configuration changes can be made.
        // Heroku will not launch new dynos if the release phase fails.
        return Ok(());
    }

    // The primary is online, access directly via `DATABASE_URL`.
    let conn = crate::db::oneoff_connection_with_config(&config)?;

    info!("Migrating the database");
    embedded_migrations::run_with_output(&conn, &mut std::io::stdout())?;

    info!("Synchronizing crate categories");
    crate::boot::categories::sync_with_connection(CATEGORIES_TOML, &conn).unwrap();

    Ok(())
}
<|endoftext|>