<commit_before>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate env_logger;
extern crate winit;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
//extern crate gfx_window_glfw;

#[cfg(target_os = "windows")]
extern crate gfx_device_dx11;
#[cfg(target_os = "windows")]
extern crate gfx_window_dxgi;

#[cfg(target_os = "macos")]
extern crate gfx_device_metal;
#[cfg(target_os = "macos")]
extern crate gfx_window_metal;

#[cfg(feature = "vulkan")]
extern crate gfx_device_vulkan;
#[cfg(feature = "vulkan")]
extern crate gfx_window_vulkan;

pub mod shade;

#[cfg(not(feature = "vulkan"))]
pub type ColorFormat = gfx::format::Rgba8;
#[cfg(feature = "vulkan")]
pub type ColorFormat = gfx::format::Bgra8;

#[cfg(target_os = "macos")]
pub type DepthFormat = gfx::format::Depth32F;
#[cfg(not(target_os = "macos"))]
pub type DepthFormat = gfx::format::DepthStencil;

pub struct Init<R: gfx::Resources> {
    pub backend: shade::Backend,
    pub color: gfx::handle::RenderTargetView<R, ColorFormat>,
    pub depth: gfx::handle::DepthStencilView<R, DepthFormat>,
    pub aspect_ratio: f32,
}

pub enum Backend {
    OpenGL2,
    Direct3D11 {
        pix_mode: bool,
    },
    Metal
}

pub struct Config {
    //pub backend: Backend,
    pub size: (u16, u16),
}

pub const DEFAULT_CONFIG: Config = Config {
    //backend: Backend::OpenGL2,
    size: (800, 520),
};

struct Harness {
    start: std::time::Instant,
    num_frames: f64,
}

impl Harness {
    fn new() -> Harness {
        Harness {
            start: std::time::Instant::now(),
            num_frames: 0.0,
        }
    }
    fn bump(&mut self) {
        self.num_frames += 1.0;
    }
}

impl Drop for Harness {
    fn drop(&mut self) {
        let time_end = self.start.elapsed();
        println!("Avg frame time: {} ms",
            ((time_end.as_secs() * 1000) as f64 + (time_end.subsec_nanos() / 1000_000) as f64) / self.num_frames
        );
    }
}

pub trait Factory<R: gfx::Resources>: gfx::Factory<R> {
    type CommandBuffer: gfx::CommandBuffer<R>;
    fn create_encoder(&mut self) -> gfx::Encoder<R, Self::CommandBuffer>;
}

pub trait ApplicationBase<R: gfx::Resources, C: gfx::CommandBuffer<R>> {
    fn new<F>(F, Init<R>) -> Self where
        F: Factory<R, CommandBuffer=C>;
    fn render<D>(&mut self, &mut D) where
        D: gfx::Device<Resources=R, CommandBuffer=C>;
}

pub trait Application<R: gfx::Resources>: Sized {
    fn new<F: gfx::Factory<R>>(F, Init<R>) -> Self;
    fn render<C: gfx::CommandBuffer<R>>(&mut self, &mut gfx::Encoder<R, C>);
    #[cfg(all(target_os = "windows", not(feature = "vulkan")))]
    fn launch_default(name: &str) where WrapD3D11<Self>: ApplicationD3D11 {
        WrapD3D11::<Self>::launch(name, DEFAULT_CONFIG);
    }
    #[cfg(all(not(target_os = "windows"), not(feature = "vulkan")))]
    fn launch_default(name: &str) where WrapGL2<Self>: ApplicationGL {
        WrapGL2::<Self>::launch(name, DEFAULT_CONFIG);
    }
    /*#[cfg(target_os = "macos")]
    fn launch_default(name: &str) where WrapMetal<Self>: ApplicationMetal {
        WrapMetal::<Self>::launch(name, DEFAULT_CONFIG)
    }*/
    #[cfg(feature = "vulkan")]
    fn launch_default(name: &str) where WrapVulkan<Self>: ApplicationVulkan {
        WrapVulkan::<Self>::launch(name, DEFAULT_CONFIG);
    }
}

pub struct Wrap<R: gfx::Resources, C: gfx::CommandBuffer<R>, A>{
    encoder: gfx::Encoder<R, C>,
    app: A,
}

#[cfg(target_os = "macos")]
pub type WrapMetal<A> = Wrap<gfx_device_metal::Resources, gfx_device_metal::CommandBuffer, A>;
#[cfg(target_os = "windows")]
pub type D3D11CommandBuffer = gfx_device_dx11::CommandBuffer<gfx_device_dx11::DeferredContext>;
#[cfg(target_os = "windows")]
pub type D3D11CommandBufferFake = gfx_device_dx11::CommandBuffer<gfx_device_dx11::CommandList>;
#[cfg(target_os = "windows")]
pub type WrapD3D11<A> = Wrap<gfx_device_dx11::Resources, D3D11CommandBuffer, A>;
pub type WrapGL2<A> = Wrap<gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, A>;
#[cfg(feature = "vulkan")]
pub type WrapVulkan<A> = Wrap<gfx_device_vulkan::Resources, gfx_device_vulkan::CommandBuffer, A>;

impl<R, C, A> ApplicationBase<R, C> for Wrap<R, C, A> where
    R: gfx::Resources,
    C: gfx::CommandBuffer<R>,
    A: Application<R>
{
    fn new<F>(mut factory: F, init: Init<R>) -> Self where
        F: Factory<R, CommandBuffer=C>,
    {
        Wrap {
            encoder: factory.create_encoder(),
            app: A::new(factory, init),
        }
    }

    fn render<D>(&mut self, device: &mut D) where
        D: gfx::Device<Resources=R, CommandBuffer=C>
    {
        self.app.render(&mut self.encoder);
        self.encoder.flush(device);
    }
}

pub trait ApplicationGL {
    fn launch(&str, Config);
}

impl Factory<gfx_device_gl::Resources> for gfx_device_gl::Factory {
    type CommandBuffer = gfx_device_gl::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_gl::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

impl<A> ApplicationGL for A where
    A: ApplicationBase<gfx_device_gl::Resources,
                       gfx_device_gl::CommandBuffer>
{
    fn launch(title: &str, config: Config) {
        use gfx::traits::Device;

        env_logger::init().unwrap();
        let gl_version = glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2), //TODO: try more versions
            opengles_version: (2, 0),
        };
        let builder = glutin::WindowBuilder::new()
            .with_title(title.to_string())
            .with_dimensions(config.size.0 as u32, config.size.1 as u32)
            .with_gl(gl_version)
            .with_vsync();
        let (window, mut device, factory, main_color, main_depth) =
            gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
        let (width, height) = window.get_inner_size().unwrap();
        let shade_lang = device.get_info().shading_language;

        let mut app = Self::new(factory, Init {
            backend: if shade_lang.is_embedded {
                shade::Backend::GlslEs(shade_lang)
            } else {
                shade::Backend::Glsl(shade_lang)
            },
            color: main_color,
            depth: main_depth,
            aspect_ratio: width as f32 / height as f32,
        });

        let mut harness = Harness::new();
        'main: loop {
            // quit when Esc is pressed.
            for event in window.poll_events() {
                match event {
                    glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                    glutin::Event::Closed => break 'main,
                    _ => {},
                }
            }
            // draw a frame
            app.render(&mut device);
            window.swap_buffers().unwrap();
            device.cleanup();
            harness.bump()
        }
    }
}

#[cfg(target_os = "windows")]
pub trait ApplicationD3D11 {
    fn launch(&str, Config);
}

#[cfg(target_os = "windows")]
impl Factory<gfx_device_dx11::Resources> for gfx_device_dx11::Factory {
    type CommandBuffer = D3D11CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_dx11::Resources, Self::CommandBuffer> {
        self.create_command_buffer_native().into()
    }
}

#[cfg(target_os = "windows")]
impl<
    A: ApplicationBase<gfx_device_dx11::Resources, D3D11CommandBuffer>
> ApplicationD3D11 for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (window, device, mut factory, main_color) =
            gfx_window_dxgi::init::<ColorFormat>(title, config.size.0, config.size.1)
            .unwrap();
        let main_depth = factory.create_depth_stencil_view_only(
            window.size.0, window.size.1).unwrap();

        let mut app = Self::new(factory, Init {
            backend: shade::Backend::Hlsl(device.get_shader_model()),
            color: main_color,
            depth: main_depth,
            aspect_ratio: window.size.0 as f32 / window.size.1 as f32,
        });
        let mut device: gfx_device_dx11::Deferred = device.into();

        let mut harness = Harness::new();
        while window.dispatch() {
            app.render(&mut device);
            window.swap_buffers(1);
            device.cleanup();
            harness.bump();
        }
    }
}

#[cfg(target_os = "macos")]
pub trait ApplicationMetal {
    fn launch(&str, Config);
}

#[cfg(target_os = "macos")]
impl Factory<gfx_device_metal::Resources> for gfx_device_metal::Factory {
    type CommandBuffer = gfx_device_meta::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_metal::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

#[cfg(target_os = "macos")]
impl<
    A: ApplicationBase<gfx_device_metal::Resources, gfx_device_metal::CommandBuffer>
> ApplicationMetal for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (window, mut device, mut factory, main_color) =
            gfx_window_metal::init::<ColorFormat>(title, config.size.0 as u32, config.size.1 as u32)
            .unwrap();

        let (width, height) = window.get_inner_size().unwrap();

        let main_depth = factory.create_depth_stencil_view_only(width as u16, height as u16).unwrap();

        let cmd_buf = factory.create_command_buffer();

        let mut app = Self::new(factory, cmd_buf.into(), Init {
            backend: shade::Backend::Msl(device.get_shader_model()),
            color: main_color,
            depth: main_depth,
            aspect_ratio: width as f32 / height as f32
        });

        let mut harness = Harness::new();
        'main: loop {
            for event in window.poll_events() {
                match event {
                    winit::Event::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape)) |
                    winit::Event::Closed => break 'main,
                    _ => {},
                }
            }

            app.render(&mut device);
            window.swap_buffers().unwrap();
            device.cleanup();
            harness.bump()
        }
    }
}

#[cfg(feature = "vulkan")]
pub trait ApplicationVulkan {
    fn launch(&str, Config);
}

#[cfg(feature = "vulkan")]
impl Factory<gfx_device_vulkan::Resources> for gfx_device_vulkan::Factory {
    type CommandBuffer = gfx_device_vulkan::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_vulkan::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

#[cfg(feature = "vulkan")]
impl<
    A: ApplicationBase<gfx_device_vulkan::Resources, gfx_device_vulkan::CommandBuffer>
> ApplicationVulkan for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (mut win, mut factory) = gfx_window_vulkan::init::<ColorFormat>(title, config.size.0 as u32, config.size.1 as u32);
        let main_depth = factory.create_depth_stencil::<DepthFormat>(config.size.0, config.size.1).unwrap();

        let mut app = Self::new(factory, Init {
            backend: shade::Backend::Vulkan,
            color: win.get_any_target(),
            depth: main_depth.2,
            aspect_ratio: config.size.0 as f32 / config.size.1 as f32, //TODO
        });

        let mut harness = Harness::new();
        'main: loop {
            for event in win.get_window().poll_events() {
                match event {
                    winit::Event::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape)) |
                    winit::Event::Closed => break 'main,
                    _ => {},
                }
            }

            let mut frame = win.start_frame();
            app.render(frame.get_queue());
            frame.get_queue().cleanup();
            harness.bump();
        }
    }
}
<commit_msg>[metal] fixed gfx_app<commit_after>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate env_logger;
extern crate winit;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
//extern crate gfx_window_glfw;

#[cfg(target_os = "windows")]
extern crate gfx_device_dx11;
#[cfg(target_os = "windows")]
extern crate gfx_window_dxgi;

#[cfg(target_os = "macos")]
extern crate gfx_device_metal;
#[cfg(target_os = "macos")]
extern crate gfx_window_metal;

#[cfg(feature = "vulkan")]
extern crate gfx_device_vulkan;
#[cfg(feature = "vulkan")]
extern crate gfx_window_vulkan;

pub mod shade;

#[cfg(not(feature = "vulkan"))]
pub type ColorFormat = gfx::format::Rgba8;
#[cfg(feature = "vulkan")]
pub type ColorFormat = gfx::format::Bgra8;

#[cfg(target_os = "macos")]
pub type DepthFormat = gfx::format::Depth32F;
#[cfg(not(target_os = "macos"))]
pub type DepthFormat = gfx::format::DepthStencil;

pub struct Init<R: gfx::Resources> {
    pub backend: shade::Backend,
    pub color: gfx::handle::RenderTargetView<R, ColorFormat>,
    pub depth: gfx::handle::DepthStencilView<R, DepthFormat>,
    pub aspect_ratio: f32,
}

pub enum Backend {
    OpenGL2,
    Direct3D11 {
        pix_mode: bool,
    },
    Metal
}

pub struct Config {
    //pub backend: Backend,
    pub size: (u16, u16),
}

pub const DEFAULT_CONFIG: Config = Config {
    //backend: Backend::OpenGL2,
    size: (800, 520),
};

struct Harness {
    start: std::time::Instant,
    num_frames: f64,
}

impl Harness {
    fn new() -> Harness {
        Harness {
            start: std::time::Instant::now(),
            num_frames: 0.0,
        }
    }
    fn bump(&mut self) {
        self.num_frames += 1.0;
    }
}

impl Drop for Harness {
    fn drop(&mut self) {
        let time_end = self.start.elapsed();
        println!("Avg frame time: {} ms",
            ((time_end.as_secs() * 1000) as f64 + (time_end.subsec_nanos() / 1000_000) as f64) / self.num_frames
        );
    }
}

pub trait Factory<R: gfx::Resources>: gfx::Factory<R> {
    type CommandBuffer: gfx::CommandBuffer<R>;
    fn create_encoder(&mut self) -> gfx::Encoder<R, Self::CommandBuffer>;
}

pub trait ApplicationBase<R: gfx::Resources, C: gfx::CommandBuffer<R>> {
    fn new<F>(F, Init<R>) -> Self where
        F: Factory<R, CommandBuffer=C>;
    fn render<D>(&mut self, &mut D) where
        D: gfx::Device<Resources=R, CommandBuffer=C>;
}

pub trait Application<R: gfx::Resources>: Sized {
    fn new<F: gfx::Factory<R>>(F, Init<R>) -> Self;
    fn render<C: gfx::CommandBuffer<R>>(&mut self, &mut gfx::Encoder<R, C>);
    #[cfg(all(target_os = "windows", not(feature = "vulkan")))]
    fn launch_default(name: &str) where WrapD3D11<Self>: ApplicationD3D11 {
        WrapD3D11::<Self>::launch(name, DEFAULT_CONFIG);
    }
    #[cfg(all(not(target_os = "windows"), not(feature = "vulkan")))]
    fn launch_default(name: &str) where WrapGL2<Self>: ApplicationGL {
        WrapGL2::<Self>::launch(name, DEFAULT_CONFIG);
    }
    /*#[cfg(target_os = "macos")]
    fn launch_default(name: &str) where WrapMetal<Self>: ApplicationMetal {
        WrapMetal::<Self>::launch(name, DEFAULT_CONFIG)
    }*/
    #[cfg(feature = "vulkan")]
    fn launch_default(name: &str) where WrapVulkan<Self>: ApplicationVulkan {
        WrapVulkan::<Self>::launch(name, DEFAULT_CONFIG);
    }
}

pub struct Wrap<R: gfx::Resources, C: gfx::CommandBuffer<R>, A>{
    encoder: gfx::Encoder<R, C>,
    app: A,
}

#[cfg(target_os = "macos")]
pub type WrapMetal<A> = Wrap<gfx_device_metal::Resources, gfx_device_metal::CommandBuffer, A>;
#[cfg(target_os = "windows")]
pub type D3D11CommandBuffer = gfx_device_dx11::CommandBuffer<gfx_device_dx11::DeferredContext>;
#[cfg(target_os = "windows")]
pub type D3D11CommandBufferFake = gfx_device_dx11::CommandBuffer<gfx_device_dx11::CommandList>;
#[cfg(target_os = "windows")]
pub type WrapD3D11<A> = Wrap<gfx_device_dx11::Resources, D3D11CommandBuffer, A>;
pub type WrapGL2<A> = Wrap<gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, A>;
#[cfg(feature = "vulkan")]
pub type WrapVulkan<A> = Wrap<gfx_device_vulkan::Resources, gfx_device_vulkan::CommandBuffer, A>;

impl<R, C, A> ApplicationBase<R, C> for Wrap<R, C, A> where
    R: gfx::Resources,
    C: gfx::CommandBuffer<R>,
    A: Application<R>
{
    fn new<F>(mut factory: F, init: Init<R>) -> Self where
        F: Factory<R, CommandBuffer=C>,
    {
        Wrap {
            encoder: factory.create_encoder(),
            app: A::new(factory, init),
        }
    }

    fn render<D>(&mut self, device: &mut D) where
        D: gfx::Device<Resources=R, CommandBuffer=C>
    {
        self.app.render(&mut self.encoder);
        self.encoder.flush(device);
    }
}

pub trait ApplicationGL {
    fn launch(&str, Config);
}

impl Factory<gfx_device_gl::Resources> for gfx_device_gl::Factory {
    type CommandBuffer = gfx_device_gl::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_gl::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

impl<A> ApplicationGL for A where
    A: ApplicationBase<gfx_device_gl::Resources,
                       gfx_device_gl::CommandBuffer>
{
    fn launch(title: &str, config: Config) {
        use gfx::traits::Device;

        env_logger::init().unwrap();
        let gl_version = glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2), //TODO: try more versions
            opengles_version: (2, 0),
        };
        let builder = glutin::WindowBuilder::new()
            .with_title(title.to_string())
            .with_dimensions(config.size.0 as u32, config.size.1 as u32)
            .with_gl(gl_version)
            .with_vsync();
        let (window, mut device, factory, main_color, main_depth) =
            gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
        let (width, height) = window.get_inner_size().unwrap();
        let shade_lang = device.get_info().shading_language;

        let mut app = Self::new(factory, Init {
            backend: if shade_lang.is_embedded {
                shade::Backend::GlslEs(shade_lang)
            } else {
                shade::Backend::Glsl(shade_lang)
            },
            color: main_color,
            depth: main_depth,
            aspect_ratio: width as f32 / height as f32,
        });

        let mut harness = Harness::new();
        'main: loop {
            // quit when Esc is pressed.
            for event in window.poll_events() {
                match event {
                    glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                    glutin::Event::Closed => break 'main,
                    _ => {},
                }
            }
            // draw a frame
            app.render(&mut device);
            window.swap_buffers().unwrap();
            device.cleanup();
            harness.bump()
        }
    }
}

#[cfg(target_os = "windows")]
pub trait ApplicationD3D11 {
    fn launch(&str, Config);
}

#[cfg(target_os = "windows")]
impl Factory<gfx_device_dx11::Resources> for gfx_device_dx11::Factory {
    type CommandBuffer = D3D11CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_dx11::Resources, Self::CommandBuffer> {
        self.create_command_buffer_native().into()
    }
}

#[cfg(target_os = "windows")]
impl<
    A: ApplicationBase<gfx_device_dx11::Resources, D3D11CommandBuffer>
> ApplicationD3D11 for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (window, device, mut factory, main_color) =
            gfx_window_dxgi::init::<ColorFormat>(title, config.size.0, config.size.1)
            .unwrap();
        let main_depth = factory.create_depth_stencil_view_only(
            window.size.0, window.size.1).unwrap();

        let mut app = Self::new(factory, Init {
            backend: shade::Backend::Hlsl(device.get_shader_model()),
            color: main_color,
            depth: main_depth,
            aspect_ratio: window.size.0 as f32 / window.size.1 as f32,
        });
        let mut device: gfx_device_dx11::Deferred = device.into();

        let mut harness = Harness::new();
        while window.dispatch() {
            app.render(&mut device);
            window.swap_buffers(1);
            device.cleanup();
            harness.bump();
        }
    }
}

#[cfg(target_os = "macos")]
pub trait ApplicationMetal {
    fn launch(&str, Config);
}

#[cfg(target_os = "macos")]
impl Factory<gfx_device_metal::Resources> for gfx_device_metal::Factory {
    type CommandBuffer = gfx_device_metal::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_metal::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

#[cfg(target_os = "macos")]
impl<
    A: ApplicationBase<gfx_device_metal::Resources, gfx_device_metal::CommandBuffer>
> ApplicationMetal for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (window, mut device, mut factory, main_color) =
            gfx_window_metal::init::<ColorFormat>(title, config.size.0 as u32, config.size.1 as u32)
            .unwrap();

        let (width, height) = window.get_inner_size().unwrap();

        let main_depth = factory.create_depth_stencil_view_only(width as u16, height as u16).unwrap();

        let mut app = Self::new(factory, Init {
            backend: shade::Backend::Msl(device.get_shader_model()),
            color: main_color,
            depth: main_depth,
            aspect_ratio: width as f32 / height as f32
        });

        let mut harness = Harness::new();
        'main: loop {
            for event in window.poll_events() {
                match event {
                    winit::Event::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape)) |
                    winit::Event::Closed => break 'main,
                    _ => {},
                }
            }

            app.render(&mut device);
            window.swap_buffers().unwrap();
            device.cleanup();
            harness.bump()
        }
    }
}

#[cfg(feature = "vulkan")]
pub trait ApplicationVulkan {
    fn launch(&str, Config);
}

#[cfg(feature = "vulkan")]
impl Factory<gfx_device_vulkan::Resources> for gfx_device_vulkan::Factory {
    type CommandBuffer = gfx_device_vulkan::CommandBuffer;
    fn create_encoder(&mut self) -> gfx::Encoder<gfx_device_vulkan::Resources, Self::CommandBuffer> {
        self.create_command_buffer().into()
    }
}

#[cfg(feature = "vulkan")]
impl<
    A: ApplicationBase<gfx_device_vulkan::Resources, gfx_device_vulkan::CommandBuffer>
> ApplicationVulkan for A {
    fn launch(title: &str, config: Config) {
        use gfx::traits::{Device, Factory};

        env_logger::init().unwrap();
        let (mut win, mut factory) = gfx_window_vulkan::init::<ColorFormat>(title, config.size.0 as u32, config.size.1 as u32);
        let main_depth = factory.create_depth_stencil::<DepthFormat>(config.size.0, config.size.1).unwrap();

        let mut app = Self::new(factory, Init {
            backend: shade::Backend::Vulkan,
            color: win.get_any_target(),
            depth: main_depth.2,
            aspect_ratio: config.size.0 as f32 / config.size.1 as f32, //TODO
        });

        let mut harness = Harness::new();
        'main: loop {
            for event in win.get_window().poll_events() {
                match event {
                    winit::Event::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape)) |
                    winit::Event::Closed => break 'main,
                    _ => {},
                }
            }

            let mut frame = win.start_frame();
            app.render(frame.get_queue());
            frame.get_queue().cleanup();
            harness.bump();
        }
    }
}
<|endoftext|>


<commit_before>static ROMAN: [(&'static str, i32); 13] = [
    ("M",  1000),
    ("CM", 900),
    ("D",  500),
    ("CD", 400),
    ("C",  100),
    ("XC", 90),
    ("L",  50),
    ("XL", 40),
    ("X",  10),
    ("IX", 9),
    ("V",  5),
    ("IV", 4),
    ("I",  1) ];

/// Converts an integer into a roman numeral.
///
/// Works for integer between 1 and 4999 inclusive, returns None otherwise.
///
/// # Example
///
/// ```
/// use roman;
///
/// let x = roman::to(14);
/// assert_eq!(x.unwrap(), "XIV");
/// ```
///
pub fn to(n: i32) -> Option<String> {
    if n <= 0 || n >= 5000 { return None }
    let mut out = String::new();
    let mut n = n;
    for i in ROMAN.iter() {
        let (name, value) = *i;
        while n >= value {
            n -= value;
            out.push_str(name);
        }
    }
    assert!(n == 0);
    Some(out)
}

#[test]
fn test_to_roman() {
    assert_eq!(to(1984).unwrap(), "MCMLXXXIV");
}
<commit_msg>Add a MAX constant<commit_after>static ROMAN: [(&'static str, i32); 13] = [
    ("M",  1000),
    ("CM", 900),
    ("D",  500),
    ("CD", 400),
    ("C",  100),
    ("XC", 90),
    ("L",  50),
    ("XL", 40),
    ("X",  10),
    ("IX", 9),
    ("V",  5),
    ("IV", 4),
    ("I",  1) ];

/// The largest number representable as a roman numeral.
pub static MAX: i32 = 4999;

/// Converts an integer into a roman numeral.
///
/// Works for integer between 1 and 4999 inclusive, returns None otherwise.
///
/// # Example
///
/// ```
/// use roman;
///
/// let x = roman::to(14);
/// assert_eq!(x.unwrap(), "XIV");
/// ```
///
pub fn to(n: i32) -> Option<String> {
    if n <= 0 || n >= 5000 { return None }
    let mut out = String::new();
    let mut n = n;
    for i in ROMAN.iter() {
        let (name, value) = *i;
        while n >= value {
            n -= value;
            out.push_str(name);
        }
    }
    assert!(n == 0);
    Some(out)
}

#[test]
fn test_to_roman() {
    assert_eq!(to(1984).unwrap(), "MCMLXXXIV");
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]
#![cfg_attr(feature = "benches", feature(test))]

extern crate mio;
extern crate bytes;
#[macro_use]
extern crate log;
extern crate serde;
extern crate serde_json;
extern crate spki_sexp;
extern crate time;

extern crate etcd;
extern crate tempdir;
extern crate rocksdb;
extern crate byteorder;

#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
extern crate env_logger;

#[cfg(feature = "benches")]
extern crate test;

use mio::tcp::*;
use mio::EventLoop;
use mio::util::Slab;
use std::collections::VecDeque;
use std::net::SocketAddr;

mod line_conn;
mod downstream_conn;
mod listener;
mod config;
mod event_handler;
mod data;
mod replication_log;
mod replica;

use line_conn::{SexpPeer, LineConn};
use downstream_conn::Downstream;
use listener::{Listener,ListenerEvents};
use event_handler::EventHandler;

use data::{Seqno,Operation,OpResp, PeerMsg, NodeViewConfig};
use config::{ConfigurationView, Epoch};

pub use config::ConfigClient;
pub use replica::ReplModel;
pub use replication_log::RocksdbLog;
pub use data::Role;

#[derive(Debug)]
pub enum ChainReplMsg {
    Operation {
        source: mio::Token,
        epoch: Epoch,
        seqno: Seqno,
        op: Vec<u8>,
    },
    ClientOperation {
        source: mio::Token,
        op: Vec<u8>,
    },
    Commit {
        source: mio::Token,
        epoch: Epoch,
        seqno: Seqno,
    },
    DownstreamResponse(OpResp),
    NewClientConn(Role, TcpStream),
}

#[derive(Debug)]
pub struct ChainRepl {
    connections: Slab<EventHandler>,
    downstream_slot: Option<mio::Token>,
    node_config: NodeViewConfig,
    new_view: Option<ConfigurationView<NodeViewConfig>>,
    model: ReplModel<RocksdbLog>,
}

impl ChainRepl {
    pub fn new(model: ReplModel<RocksdbLog>) -> ChainRepl {
        ChainRepl {
            connections: Slab::new(1024),
            downstream_slot: None,
            node_config: Default::default(),
            new_view: None,
            model: model,
        }
    }

    pub fn listen(&mut self,
                  event_loop: &mut mio::EventLoop<ChainRepl>,
                  addr: SocketAddr,
                  role: Role) {
        info!("Listen on {:?} for {:?}", addr, role);
        let &mut ChainRepl { ref mut connections, ref mut node_config, .. } = self;
        let token = connections.insert_with(|token| {
                                   let l = Listener::new(addr, token, role.clone());
                                   match role {
                                       Role::Upstream => {
                                           node_config.peer_addr = Some(format!("{}",
                                                                                l.listen_addr()))
                                       }
                                       Role::Client => {
                                           node_config.client_addr = Some(format!("{}",
                                                                                l.listen_addr()))
                                       }
                                   }

                                   EventHandler::Listener(l)
                               })
                               .expect("insert listener");
        connections[token].initialize(event_loop, token);
    }

    pub fn set_downstream(&mut self,
                          event_loop: &mut mio::EventLoop<ChainRepl>,
                          target: Option<SocketAddr>) {
        match (self.downstream_slot, target) {
            (Some(_), Some(target)) => self.downstream().expect("downstream").reconnect_to(target),
            (None, Some(target)) => {
                let token = self.connections
                                .insert_with(|token| {
                                    EventHandler::Downstream(Downstream::new(Some(target), token))
                                })
                                .expect("insert downstream");
                &self.connections[token].initialize(event_loop, token);
                self.downstream_slot = Some(token)
            }
            (Some(_), None) => self.downstream().expect("downstream").disconnect(),
            (None, None) => (),
        }
    }

    fn process_action(&mut self, msg: ChainReplMsg, event_loop: &mut mio::EventLoop<ChainRepl>) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            ChainReplMsg::Operation { source, seqno, epoch, op } => {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                model.process_operation(&mut out, source, seqno, epoch, &op)
            }
            ChainReplMsg::ClientOperation { source, op } => {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                model.process_client(&mut out, source, &op)
            }

            ChainReplMsg::Commit { seqno, .. } => {
                self.model.commit_observed(seqno);
            }

            ChainReplMsg::DownstreamResponse(reply) => self.process_downstream_response(reply),

            ChainReplMsg::NewClientConn(role, socket) => {
                self.process_new_client_conn(event_loop, role, socket)
            }
        }
    }

    fn process_downstream_response(&mut self, reply: OpResp) {
        trace!("Downstream response: {:?}", reply);
        let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
        let mut out = OutPorts(self.downstream_slot, connections);

        model.process_downstream_response(&mut out, reply)
    }

    fn process_new_client_conn(&mut self,
                               event_loop: &mut mio::EventLoop<ChainRepl>,
                               role: Role,
                               socket: TcpStream) {
        let peer = socket.peer_addr().expect("peer address");
        let seqno = self.model.seqno();
        trace!("process_new_client_conn: {:?}@{:?}", role, peer);

        let token = self.connections
                        .insert_with(|token| {
                            match role {
                                Role::Client => EventHandler::Conn(LineConn::client(socket, token)),
                                Role::Upstream => {
                                    let mut conn = LineConn::upstream(socket, token);
                                    let msg = OpResp::HelloIWant(seqno);
                                    info!("Inform upstream about our current version, {:?}!", msg);
                                    conn.response(msg);
                                    EventHandler::Upstream(conn)
                                }
                            }
                        })
                        .expect("token insert");
        trace!("Client connection of {:?}/{:?} from {:?}",
               role,
               token,
               peer);
        &self.connections[token].initialize(event_loop, token);
    }

    fn reconfigure(&mut self,
                   event_loop: &mut mio::EventLoop<Self>,
                   view: ConfigurationView<NodeViewConfig>) {
        info!("Reconfigure according to: {:?}", view);

        let listen_for_clients = view.should_listen_for_clients();
        info!("Listen for clients: {:?}", listen_for_clients);
        for p in self.listeners(Role::Client) {
            trace!("Active: {:?} -> {:?}", p, listen_for_clients);
            p.set_active(listen_for_clients);
        }

        let listen_for_upstreamp = view.should_listen_for_upstream();
        info!("Listen for upstreams: {:?}", listen_for_upstreamp);
        for p in self.listeners(Role::Upstream) {
            trace!("Active: {:?} -> {:?}", p, listen_for_clients);
            p.set_active(listen_for_upstreamp);
        }

        if let Some(ds) = view.should_connect_downstream() {
            info!("Push to downstream on {:?}", ds);
            let peer_addr = ds.peer_addr.as_ref().expect("Cannot reconnect to downstream with no peer listener");
            self.set_downstream(event_loop, Some(peer_addr.parse().expect("peer address")));
        } else {
            info!("Tail node!");
            self.set_downstream(event_loop, None);
        }

        info!("Reconfigure model: {:?}", view);
        self.model.reconfigure(view)
    }

    fn downstream<'a>(&'a mut self) -> Option<&'a mut Downstream<SexpPeer>> {
        self.downstream_slot.map(move |slot| {
            match &mut self.connections[slot] {
                &mut EventHandler::Downstream(ref mut d) => d,
                other => {
                    panic!("Downstream slot not populated with a downstream instance: {:?}",
                           other)
                }
            }
        })
    }

    fn listeners<'a>(&'a mut self, role: Role) -> Vec<&'a mut Listener> {
        self.connections
            .iter_mut()
            .filter_map(|it| {
                match it {
                    &mut EventHandler::Listener(ref mut l) if l.role == role => Some(l),
                    _ => None,
                }
            })
            .collect()
    }

    fn process_rules(&mut self, event_loop: &mut mio::EventLoop<Self>)
                                             -> bool {
        let mut changed = false;

        if let Some(view) = self.new_view.take() {
            self.reconfigure(event_loop, view);
            changed |= true;
        }

        changed
    }

    fn converge_state(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        let mut parent_actions = VecDeque::new();
        let mut changed = true;
        let mut iterations = 0;
        trace!("Converge begin");
        while changed {
            trace!("Iter: {:?}", iterations);
            changed = false;
            {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                struct ChainReplEvents { changes: VecDeque<ChainReplMsg> };
                impl ListenerEvents for ChainReplEvents {
                    fn new_connection(&mut self, role: Role, socket: TcpStream) {
                        self.changes.push_back(ChainReplMsg::NewClientConn(role, socket))
                    }
                }
                let mut events = ChainReplEvents { changes: VecDeque::new() };
                for conn in connections.iter_mut() {
                    changed |= conn.process_rules(event_loop,
                                                      &mut |item| parent_actions.push_back(item),
                                                      &mut events);
                }
            }

            changed |= self.process_rules(event_loop);

            {

                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                changed |= model.process_replication(&mut out);

                changed |= model.flush();
            }

            trace!("Actions pending: {:?}", parent_actions.len());
            for action in parent_actions.drain(..) {
                trace!("Action: {:?}", action);
                self.process_action(action, event_loop);
            }
            iterations += 1;
        }
        trace!("Converged after {:?} iterations", iterations);
    }

    fn io_ready(&mut self, event_loop: &mut mio::EventLoop<Self>, token: mio::Token) {
        self.converge_state(event_loop);
        if self.connections[token].should_close() && self.model.has_pending(token) {
            trace!("Close candidate: {:?}", token);
            let it = self.connections.remove(token);
            trace!("Removing; {:?}; {:?}", token, it);
            if Some(token) == self.downstream_slot {
                self.downstream_slot = None;
                self.model.reset();
            }
        }
    }

    fn handle_view_changed(&mut self, view: ConfigurationView<NodeViewConfig>) {
        self.new_view = Some(view)
    }

    fn committed_to(&mut self, seqno: Seqno) {
        info!("Committed upto: {:?}", seqno);
    }
    pub fn get_notifier(event_loop: &mut mio::EventLoop<Self>) -> Notifier {
        Notifier(event_loop.channel())
    }

    pub fn node_config(&self) -> NodeViewConfig {
        self.node_config.clone()
    }
}

#[derive(Debug)]
pub enum Notification {
    ViewChange(ConfigurationView<NodeViewConfig>),
    Shutdown,
    CommittedTo(Seqno),
}
pub struct Notifier(mio::Sender<Notification>);

impl Notifier {
    fn notify(&self, mut item: Notification) {
        use mio::NotifyError::*;
        use std::time::Duration;
        let mut backoff = Duration::from_millis(1);
        loop {
            item = match self.0.send(item) {
                Ok(_) => return,
                Err(Full(it)) => it,
                Err(e) => panic!("{:?}", e),
            };
            info!("Backoff: {:?}", backoff);
            std::thread::sleep(backoff);
            backoff = backoff * 2;
        }
    }

    pub fn view_changed(&self, view: ConfigurationView<NodeViewConfig>) {
        self.notify(Notification::ViewChange(view))
    }
    pub fn shutdown(&self) {
        self.notify(Notification::Shutdown)
    }
    pub fn committed_to(&self, seqno: Seqno) {
        self.notify(Notification::CommittedTo(seqno))
    }
}

struct OutPorts<'a>(Option<mio::Token>, &'a mut Slab<event_handler::EventHandler>);

impl<'a> replica::Outputs for OutPorts<'a> {
    fn respond_to(&mut self, token: mio::Token, resp: OpResp) {
        let &mut OutPorts(downstream, ref mut conns) = self;
        trace!("respond_to: {:?} -> {:?}", token, resp);
        conns[token].response(resp);
    }

    fn forward_downstream(&mut self, epoch: Epoch, msg: PeerMsg) {
        let &mut OutPorts(downstream, ref mut conns) = self;
        trace!("forward_downstream: @{:?} -> {:?}", epoch, msg);

        let slot = downstream.expect("downstream_slot");
        let ds = match &mut conns[slot] {
            &mut EventHandler::Downstream(ref mut d) => d,
            other => {
                panic!("Downstream slot not populated with a downstream instance: {:?}",
                        other)
            }
        };
        ds.send_to_downstream(epoch, msg)
    }
}

impl mio::Handler for ChainRepl {
    // This is a bit wierd; we can pass a parent action back to enqueue some action.
    type Timeout = mio::Token;
    type Message = Notification;
    fn ready(&mut self,
             event_loop: &mut mio::EventLoop<Self>,
             token: mio::Token,
             events: mio::EventSet) {
        trace!("{:?}: {:?}", token, events);
        self.connections[token].handle_event(event_loop, events);
        self.io_ready(event_loop, token);
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Self>, token: mio::Token) {
        trace!("Timeout: {:?}", token);
        self.connections[token].handle_timeout();
        self.io_ready(event_loop, token);
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        trace!("Notified: {:?}", msg);
        match msg {
            Notification::ViewChange(view) => self.handle_view_changed(view),
            Notification::CommittedTo(seqno) => self.committed_to(seqno),
            Notification::Shutdown => {
                info!("Shutting down");
                event_loop.shutdown();
            }
        }
        self.converge_state(event_loop);
    }
}
<commit_msg>Fix minor bug with actions being ignored.<commit_after>#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]
#![cfg_attr(feature = "benches", feature(test))]

extern crate mio;
extern crate bytes;
#[macro_use]
extern crate log;
extern crate serde;
extern crate serde_json;
extern crate spki_sexp;
extern crate time;

extern crate etcd;
extern crate tempdir;
extern crate rocksdb;
extern crate byteorder;

#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
extern crate env_logger;

#[cfg(feature = "benches")]
extern crate test;

use mio::tcp::*;
use mio::EventLoop;
use mio::util::Slab;
use std::collections::VecDeque;
use std::net::SocketAddr;

mod line_conn;
mod downstream_conn;
mod listener;
mod config;
mod event_handler;
mod data;
mod replication_log;
mod replica;

use line_conn::{SexpPeer, LineConn};
use downstream_conn::Downstream;
use listener::{Listener,ListenerEvents};
use event_handler::EventHandler;

use data::{Seqno,Operation,OpResp, PeerMsg, NodeViewConfig};
use config::{ConfigurationView, Epoch};

pub use config::ConfigClient;
pub use replica::ReplModel;
pub use replication_log::RocksdbLog;
pub use data::Role;

#[derive(Debug)]
pub enum ChainReplMsg {
    Operation {
        source: mio::Token,
        epoch: Epoch,
        seqno: Seqno,
        op: Vec<u8>,
    },
    ClientOperation {
        source: mio::Token,
        op: Vec<u8>,
    },
    Commit {
        source: mio::Token,
        epoch: Epoch,
        seqno: Seqno,
    },
    DownstreamResponse(OpResp),
    NewClientConn(Role, TcpStream),
}

#[derive(Debug)]
pub struct ChainRepl {
    connections: Slab<EventHandler>,
    downstream_slot: Option<mio::Token>,
    node_config: NodeViewConfig,
    new_view: Option<ConfigurationView<NodeViewConfig>>,
    model: ReplModel<RocksdbLog>,
}

impl ChainRepl {
    pub fn new(model: ReplModel<RocksdbLog>) -> ChainRepl {
        ChainRepl {
            connections: Slab::new(1024),
            downstream_slot: None,
            node_config: Default::default(),
            new_view: None,
            model: model,
        }
    }

    pub fn listen(&mut self,
                  event_loop: &mut mio::EventLoop<ChainRepl>,
                  addr: SocketAddr,
                  role: Role) {
        info!("Listen on {:?} for {:?}", addr, role);
        let &mut ChainRepl { ref mut connections, ref mut node_config, .. } = self;
        let token = connections.insert_with(|token| {
                                   let l = Listener::new(addr, token, role.clone());
                                   match role {
                                       Role::Upstream => {
                                           node_config.peer_addr = Some(format!("{}",
                                                                                l.listen_addr()))
                                       }
                                       Role::Client => {
                                           node_config.client_addr = Some(format!("{}",
                                                                                l.listen_addr()))
                                       }
                                   }

                                   EventHandler::Listener(l)
                               })
                               .expect("insert listener");
        connections[token].initialize(event_loop, token);
    }

    pub fn set_downstream(&mut self,
                          event_loop: &mut mio::EventLoop<ChainRepl>,
                          target: Option<SocketAddr>) {
        match (self.downstream_slot, target) {
            (Some(_), Some(target)) => self.downstream().expect("downstream").reconnect_to(target),
            (None, Some(target)) => {
                let token = self.connections
                                .insert_with(|token| {
                                    EventHandler::Downstream(Downstream::new(Some(target), token))
                                })
                                .expect("insert downstream");
                &self.connections[token].initialize(event_loop, token);
                self.downstream_slot = Some(token)
            }
            (Some(_), None) => self.downstream().expect("downstream").disconnect(),
            (None, None) => (),
        }
    }

    fn process_action(&mut self, msg: ChainReplMsg, event_loop: &mut mio::EventLoop<ChainRepl>) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            ChainReplMsg::Operation { source, seqno, epoch, op } => {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                model.process_operation(&mut out, source, seqno, epoch, &op)
            }
            ChainReplMsg::ClientOperation { source, op } => {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                model.process_client(&mut out, source, &op)
            }

            ChainReplMsg::Commit { seqno, .. } => {
                self.model.commit_observed(seqno);
            }

            ChainReplMsg::DownstreamResponse(reply) => self.process_downstream_response(reply),

            ChainReplMsg::NewClientConn(role, socket) => {
                self.process_new_client_conn(event_loop, role, socket)
            }
        }
    }

    fn process_downstream_response(&mut self, reply: OpResp) {
        trace!("Downstream response: {:?}", reply);
        let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
        let mut out = OutPorts(self.downstream_slot, connections);

        model.process_downstream_response(&mut out, reply)
    }

    fn process_new_client_conn(&mut self,
                               event_loop: &mut mio::EventLoop<ChainRepl>,
                               role: Role,
                               socket: TcpStream) {
        let peer = socket.peer_addr().expect("peer address");
        let seqno = self.model.seqno();
        trace!("process_new_client_conn: {:?}@{:?}", role, peer);

        let token = self.connections
                        .insert_with(|token| {
                            match role {
                                Role::Client => EventHandler::Conn(LineConn::client(socket, token)),
                                Role::Upstream => {
                                    let mut conn = LineConn::upstream(socket, token);
                                    let msg = OpResp::HelloIWant(seqno);
                                    info!("Inform upstream about our current version, {:?}!", msg);
                                    conn.response(msg);
                                    EventHandler::Upstream(conn)
                                }
                            }
                        })
                        .expect("token insert");
        trace!("Client connection of {:?}/{:?} from {:?}",
               role,
               token,
               peer);
        &self.connections[token].initialize(event_loop, token);
    }

    fn reconfigure(&mut self,
                   event_loop: &mut mio::EventLoop<Self>,
                   view: ConfigurationView<NodeViewConfig>) {
        info!("Reconfigure according to: {:?}", view);

        let listen_for_clients = view.should_listen_for_clients();
        info!("Listen for clients: {:?}", listen_for_clients);
        for p in self.listeners(Role::Client) {
            trace!("Active: {:?} -> {:?}", p, listen_for_clients);
            p.set_active(listen_for_clients);
        }

        let listen_for_upstreamp = view.should_listen_for_upstream();
        info!("Listen for upstreams: {:?}", listen_for_upstreamp);
        for p in self.listeners(Role::Upstream) {
            trace!("Active: {:?} -> {:?}", p, listen_for_clients);
            p.set_active(listen_for_upstreamp);
        }

        if let Some(ds) = view.should_connect_downstream() {
            info!("Push to downstream on {:?}", ds);
            let peer_addr = ds.peer_addr.as_ref().expect("Cannot reconnect to downstream with no peer listener");
            self.set_downstream(event_loop, Some(peer_addr.parse().expect("peer address")));
        } else {
            info!("Tail node!");
            self.set_downstream(event_loop, None);
        }

        info!("Reconfigure model: {:?}", view);
        self.model.reconfigure(view)
    }

    fn downstream<'a>(&'a mut self) -> Option<&'a mut Downstream<SexpPeer>> {
        self.downstream_slot.map(move |slot| {
            match &mut self.connections[slot] {
                &mut EventHandler::Downstream(ref mut d) => d,
                other => {
                    panic!("Downstream slot not populated with a downstream instance: {:?}",
                           other)
                }
            }
        })
    }

    fn listeners<'a>(&'a mut self, role: Role) -> Vec<&'a mut Listener> {
        self.connections
            .iter_mut()
            .filter_map(|it| {
                match it {
                    &mut EventHandler::Listener(ref mut l) if l.role == role => Some(l),
                    _ => None,
                }
            })
            .collect()
    }

    fn process_rules(&mut self, event_loop: &mut mio::EventLoop<Self>)
                                             -> bool {
        let mut changed = false;

        if let Some(view) = self.new_view.take() {
            self.reconfigure(event_loop, view);
            changed |= true;
        }

        changed
    }

    fn converge_state(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        struct ChainReplEvents { changes: VecDeque<ChainReplMsg> };
        impl ListenerEvents for ChainReplEvents {
            fn new_connection(&mut self, role: Role, socket: TcpStream) {
                self.changes.push_back(ChainReplMsg::NewClientConn(role, socket))
            }
        }

        let mut parent_actions = VecDeque::new();
        let mut changed = true;
        let mut iterations = 0;
        trace!("Converge begin");

        while changed {
            trace!("Iter: {:?}", iterations);
            changed = false;
            let mut events = ChainReplEvents { changes: VecDeque::new() };
            {
                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                for conn in connections.iter_mut() {
                    changed |= conn.process_rules(event_loop,
                                                      &mut |item| parent_actions.push_back(item),
                                                      &mut events);
                }
            }

            changed |= self.process_rules(event_loop);

            {

                let &mut ChainRepl { ref mut model, ref mut connections, .. } = self;
                let mut out = OutPorts(self.downstream_slot, connections);
                changed |= model.process_replication(&mut out);

                changed |= model.flush();
            }

            trace!("Actions pending: {:?}+{:?}", parent_actions.len(), events.changes.len());
            for action in parent_actions.drain(..).chain(events.changes.drain(..)) {
                trace!("Action: {:?}", action);
                self.process_action(action, event_loop);
            }
            iterations += 1;
        }
        trace!("Converged after {:?} iterations", iterations);
    }

    fn io_ready(&mut self, event_loop: &mut mio::EventLoop<Self>, token: mio::Token) {
        self.converge_state(event_loop);
        if self.connections[token].should_close() && self.model.has_pending(token) {
            trace!("Close candidate: {:?}", token);
            let it = self.connections.remove(token);
            trace!("Removing; {:?}; {:?}", token, it);
            if Some(token) == self.downstream_slot {
                self.downstream_slot = None;
                self.model.reset();
            }
        }
    }

    fn handle_view_changed(&mut self, view: ConfigurationView<NodeViewConfig>) {
        self.new_view = Some(view)
    }

    fn committed_to(&mut self, seqno: Seqno) {
        info!("Committed upto: {:?}", seqno);
    }
    pub fn get_notifier(event_loop: &mut mio::EventLoop<Self>) -> Notifier {
        Notifier(event_loop.channel())
    }

    pub fn node_config(&self) -> NodeViewConfig {
        self.node_config.clone()
    }
}

#[derive(Debug)]
pub enum Notification {
    ViewChange(ConfigurationView<NodeViewConfig>),
    Shutdown,
    CommittedTo(Seqno),
}
pub struct Notifier(mio::Sender<Notification>);

impl Notifier {
    fn notify(&self, mut item: Notification) {
        use mio::NotifyError::*;
        use std::time::Duration;
        let mut backoff = Duration::from_millis(1);
        loop {
            item = match self.0.send(item) {
                Ok(_) => return,
                Err(Full(it)) => it,
                Err(e) => panic!("{:?}", e),
            };
            info!("Backoff: {:?}", backoff);
            std::thread::sleep(backoff);
            backoff = backoff * 2;
        }
    }

    pub fn view_changed(&self, view: ConfigurationView<NodeViewConfig>) {
        self.notify(Notification::ViewChange(view))
    }
    pub fn shutdown(&self) {
        self.notify(Notification::Shutdown)
    }
    pub fn committed_to(&self, seqno: Seqno) {
        self.notify(Notification::CommittedTo(seqno))
    }
}

struct OutPorts<'a>(Option<mio::Token>, &'a mut Slab<event_handler::EventHandler>);

impl<'a> replica::Outputs for OutPorts<'a> {
    fn respond_to(&mut self, token: mio::Token, resp: OpResp) {
        let &mut OutPorts(downstream, ref mut conns) = self;
        trace!("respond_to: {:?} -> {:?}", token, resp);
        conns[token].response(resp);
    }

    fn forward_downstream(&mut self, epoch: Epoch, msg: PeerMsg) {
        let &mut OutPorts(downstream, ref mut conns) = self;
        trace!("forward_downstream: @{:?} -> {:?}", epoch, msg);

        let slot = downstream.expect("downstream_slot");
        let ds = match &mut conns[slot] {
            &mut EventHandler::Downstream(ref mut d) => d,
            other => {
                panic!("Downstream slot not populated with a downstream instance: {:?}",
                        other)
            }
        };
        ds.send_to_downstream(epoch, msg)
    }
}

impl mio::Handler for ChainRepl {
    // This is a bit wierd; we can pass a parent action back to enqueue some action.
    type Timeout = mio::Token;
    type Message = Notification;
    fn ready(&mut self,
             event_loop: &mut mio::EventLoop<Self>,
             token: mio::Token,
             events: mio::EventSet) {
        trace!("{:?}: {:?}", token, events);
        self.connections[token].handle_event(event_loop, events);
        self.io_ready(event_loop, token);
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Self>, token: mio::Token) {
        trace!("Timeout: {:?}", token);
        self.connections[token].handle_timeout();
        self.io_ready(event_loop, token);
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        trace!("Notified: {:?}", msg);
        match msg {
            Notification::ViewChange(view) => self.handle_view_changed(view),
            Notification::CommittedTo(seqno) => self.committed_to(seqno),
            Notification::Shutdown => {
                info!("Shutting down");
                event_loop.shutdown();
            }
        }
        self.converge_state(event_loop);
    }
}
<|endoftext|>


<commit_before>//! A crate that provides support for half-precision 16-bit floating point types.
//!
//! This crate provides the [`f16`] type, which is an implementation of the IEEE 754-2008 standard
//! [`binary16`] a.k.a `half` floating point type. This 16-bit floating point type is intended for
//! efficient storage where the full range and precision of a larger floating point value is not
//! required. This is especially useful for image storage formats.
//!
//! This crate also provides a [`bf16`] type, an alternative 16-bit floating point format. The
//! [`bfloat16`] format is a truncated IEEE 754 standard `binary32` float that preserves the
//! exponent to allow the same range as `f32` but with only 8 bits of precision (instead of 11
//! bits for [`f16`]). See the [`bf16`] type for details.
//!
//! Because [`f16`] and [`bf16`] are primarily for efficient storage, floating point operations such as
//! addition, multiplication, etc. are not implemented. Operations should be performed with `f32`
//! or higher-precision types and converted to/from [`f16`] or [`bf16`] as necessary.
//!
//! This crate also provides a [`slice`] module for zero-copy in-place conversions of `u16` slices
//! to both [`f16`] and [`bf16`], as well as efficient vectorized conversions of larger buffers of
//! floating point values to and from these half formats.
//!
//! A [`prelude`] module is provided for easy importing of available utility traits.
//!
//! Some hardware architectures provide support for 16-bit floating point conversions. Enable the
//! `use-intrinsics` feature to use LLVM intrinsics for hardware conversions. This crate does no
//! checks on whether the hardware supports the feature. This feature currently only works on
//! nightly Rust due to a compiler feature gate. When this feature is enabled and the hardware
//! supports it, the [`slice`] trait conversions will use vectorized SIMD intructions for
//! increased efficiency.
//!
//! Support for [`serde`] crate `Serialize` and `Deserialize` traits is provided when the `serde`
//! feature is enabled. This adds a dependency on [`serde`] crate so is an optional cargo feature.
//! Support for [`bytemuck`] crate `Zeroable` and `Pod` traits is provided with the `bytemuck`
//! feature. Support for the [`num-traits`] crate `ToPrimitive` and `FromPrimitive` traits is
//! provided with the `num-traits` feature.
//!
//! The crate uses `#[no_std]` by default, so can be used in embedded environments without using the
//! Rust `std` library. A `std` feature is available, which enables additional utilities using the
//! `std` library, such as the [`vec`] module that provides zero-copy `Vec` conversions. The `alloc`
//! feature may be used to enable the [`vec`] module without adding a dependency to the `std`
//! library.
//!
//! [`f16`]: struct.f16.html
//! [`binary16`]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
//! [`bf16`]: struct.bf16.html
//! [`bfloat16`]: https://en.wikipedia.org/wiki/Bfloat16_floating-point_format
//! [`slice`]: slice/index.html
//! [`prelude`]: prelude/index.html
//! [`serde`]: https://crates.io/crates/serde
//! [`bytemuck`]: https://crates.io/crates/bytemuck
//! [`num-traits`]: https://crates.io/crates/num-traits
//! [`vec`]: vec/index.html

#![warn(
    missing_docs,
    missing_copy_implementations,
    missing_debug_implementations,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    future_incompatible,
    rust_2018_compatibility,
    rust_2018_idioms,
    clippy::all
)]
#![allow(clippy::verbose_bit_mask, clippy::cast_lossless)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(
    all(
        feature = "use-intrinsics",
        any(target_arch = "x86", target_arch = "x86_64")
    ),
    feature(stdsimd, f16c_target_feature)
)]
#![doc(html_root_url = "https://docs.rs/half/1.7.1")]

#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;

mod bfloat;
mod binary16;
pub mod slice;
#[cfg(any(feature = "alloc", feature = "std"))]
pub mod vec;

pub use binary16::f16;

#[allow(deprecated)]
pub use binary16::consts;

pub use bfloat::bf16;

/// A collection of the most used items and traits in this crate for easy importing.
///
/// # Examples
///
/// ```rust
/// use half::prelude::*;
/// ```
pub mod prelude {
    #[doc(no_inline)]
    pub use crate::{
        bf16, f16,
        slice::{HalfBitsSliceExt, HalfFloatSliceExt},
    };

    #[cfg(any(feature = "alloc", feature = "std"))]
    pub use crate::vec::{HalfBitsVecExt, HalfFloatVecExt};
}

// Keep this module private to crate
pub(crate) mod private {
    use crate::{bf16, f16};

    pub trait SealedHalf {}

    impl SealedHalf for f16 {}
    impl SealedHalf for bf16 {}
}
<commit_msg>mention AsPrimitive in the documentation<commit_after>//! A crate that provides support for half-precision 16-bit floating point types.
//!
//! This crate provides the [`f16`] type, which is an implementation of the IEEE 754-2008 standard
//! [`binary16`] a.k.a `half` floating point type. This 16-bit floating point type is intended for
//! efficient storage where the full range and precision of a larger floating point value is not
//! required. This is especially useful for image storage formats.
//!
//! This crate also provides a [`bf16`] type, an alternative 16-bit floating point format. The
//! [`bfloat16`] format is a truncated IEEE 754 standard `binary32` float that preserves the
//! exponent to allow the same range as `f32` but with only 8 bits of precision (instead of 11
//! bits for [`f16`]). See the [`bf16`] type for details.
//!
//! Because [`f16`] and [`bf16`] are primarily for efficient storage, floating point operations such as
//! addition, multiplication, etc. are not implemented. Operations should be performed with `f32`
//! or higher-precision types and converted to/from [`f16`] or [`bf16`] as necessary.
//!
//! This crate also provides a [`slice`] module for zero-copy in-place conversions of `u16` slices
//! to both [`f16`] and [`bf16`], as well as efficient vectorized conversions of larger buffers of
//! floating point values to and from these half formats.
//!
//! A [`prelude`] module is provided for easy importing of available utility traits.
//!
//! Some hardware architectures provide support for 16-bit floating point conversions. Enable the
//! `use-intrinsics` feature to use LLVM intrinsics for hardware conversions. This crate does no
//! checks on whether the hardware supports the feature. This feature currently only works on
//! nightly Rust due to a compiler feature gate. When this feature is enabled and the hardware
//! supports it, the [`slice`] trait conversions will use vectorized SIMD intructions for
//! increased efficiency.
//!
//! Support for [`serde`] crate `Serialize` and `Deserialize` traits is provided when the `serde`
//! feature is enabled. This adds a dependency on [`serde`] crate so is an optional cargo feature.
//! Support for [`bytemuck`] crate `Zeroable` and `Pod` traits is provided with the `bytemuck`
//! feature. Support for the [`num-traits`] crate `ToPrimitive`, `FromPrimitive`, and `AsPrimitive`
//! traits is provided with the `num-traits` feature.
//!
//! The crate uses `#[no_std]` by default, so can be used in embedded environments without using the
//! Rust `std` library. A `std` feature is available, which enables additional utilities using the
//! `std` library, such as the [`vec`] module that provides zero-copy `Vec` conversions. The `alloc`
//! feature may be used to enable the [`vec`] module without adding a dependency to the `std`
//! library.
//!
//! [`f16`]: struct.f16.html
//! [`binary16`]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
//! [`bf16`]: struct.bf16.html
//! [`bfloat16`]: https://en.wikipedia.org/wiki/Bfloat16_floating-point_format
//! [`slice`]: slice/index.html
//! [`prelude`]: prelude/index.html
//! [`serde`]: https://crates.io/crates/serde
//! [`bytemuck`]: https://crates.io/crates/bytemuck
//! [`num-traits`]: https://crates.io/crates/num-traits
//! [`vec`]: vec/index.html

#![warn(
    missing_docs,
    missing_copy_implementations,
    missing_debug_implementations,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    future_incompatible,
    rust_2018_compatibility,
    rust_2018_idioms,
    clippy::all
)]
#![allow(clippy::verbose_bit_mask, clippy::cast_lossless)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(
    all(
        feature = "use-intrinsics",
        any(target_arch = "x86", target_arch = "x86_64")
    ),
    feature(stdsimd, f16c_target_feature)
)]
#![doc(html_root_url = "https://docs.rs/half/1.7.1")]

#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;

mod bfloat;
mod binary16;
pub mod slice;
#[cfg(any(feature = "alloc", feature = "std"))]
pub mod vec;

pub use binary16::f16;

#[allow(deprecated)]
pub use binary16::consts;

pub use bfloat::bf16;

/// A collection of the most used items and traits in this crate for easy importing.
///
/// # Examples
///
/// ```rust
/// use half::prelude::*;
/// ```
pub mod prelude {
    #[doc(no_inline)]
    pub use crate::{
        bf16, f16,
        slice::{HalfBitsSliceExt, HalfFloatSliceExt},
    };

    #[cfg(any(feature = "alloc", feature = "std"))]
    pub use crate::vec::{HalfBitsVecExt, HalfFloatVecExt};
}

// Keep this module private to crate
pub(crate) mod private {
    use crate::{bf16, f16};

    pub trait SealedHalf {}

    impl SealedHalf for f16 {}
    impl SealedHalf for bf16 {}
}
<|endoftext|>


<commit_before>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}
<commit_msg>Added the digamma function for real numbers<commit_after>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

/// Compute the real valued digamma function. `d/dx ln Gamma(x)`.
/// Appriximation based on Beal, Matthew J. (2003). *Variational
/// Algorithms for Approximate Bayesian Inference* (PhD thesis). The
/// Gatsby Computational Neuroscience Unit, University College
/// London. pp. 265–266
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
#[inline]
pub fn digamma(x: f64)-> f64 {
    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x.powi(2);
        x.ln() - 0.5*inv_x - inv_x_e2 * (0.08333333333333333
                                         - 0.008333333333333333 * inv_x_e2
                                         + 0.003968253968253968 * inv_x_e2.powi(2)
                                         - 0.004166666666666667 * inv_x_e2.powi(3)
                                         + 0.007575757575757576 * inv_x_e2.powi(4)
                                         - 0.021092796092796094 * inv_x_e2.powi(5)
                                         + 0.08333333333333333 * inv_x_e2.powi(6)
                                         - 0.4432598039215686 * inv_x_e2.powi(7))
    } else {
        // Shift by recurrence
        digamma(x + 1.0) - x.recip()
    }
}

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

    #[test]
    fn test_digamma() {
        use std::f64::consts::{ FRAC_PI_2, LN_2 };
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, digamma(0.25));
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

// offsetof()-like operation. Will become obsolete when-and-if offsetof() is
// implemented in the core language.
pub macro_rules! field_offset(
    ($container:ty . $field:ident : $fieldtype:ty) => (unsafe {
        let nullptr = 0 as * const $container;
        let fieldptr: * const $fieldtype = &((*nullptr).$field);
        fieldptr.to_uint()
    })
)
// container_of()-like operation. The field should go out of scope as the
// container enters scope.
pub macro_rules! from_field(
    ($name:ident($container:ty . $field:ident : $fieldtype:ty)) =>
    (fn $name(arg: &$fieldtype) -> &$container {
        unsafe {
            let argp: * const $fieldtype = &*arg;
            let argi = argp.to_uint();
            let containeri =
                argi - field_offset!($container.$field:$fieldtype);
            let containerp: * const $container =
                containeri as * const $container;
            &*containerp
        }
    })
)

#[cfg(test)]
pub mod test {
    pub struct MyStruct {
        field1: i32,
        field2: i32,
        field3: i32,
    }

    impl MyStruct {
        pub fn field1_offset() -> uint {
            field_offset!(MyStruct.field1:i32)
        }
        pub fn field2_offset() -> uint {
            field_offset!(MyStruct.field2:i32)
        }
        pub fn field3_offset() -> uint {
            field_offset!(MyStruct.field3:i32)
        }
        fn from_field1_meth1(field1: &i32) -> &MyStruct {
            unsafe {
                let field1p: * const i32 = &*field1;
                let field1i = field1p.to_uint();
                let selfptr = field1i - field_offset!(MyStruct.field1:i32);
                let typedselfptr: * const MyStruct =
                    selfptr as * const MyStruct;
                &(*typedselfptr)
            }
        }
        from_field!(from_field1_meth2(MyStruct.field1:i32))
        from_field!(from_field2(MyStruct.field2:i32))
        from_field!(from_field3(MyStruct.field3:i32))
        to_field!(to_field1(MyStruct.field1:i32))
        to_field!(to_field2(MyStruct.field2:i32))
        to_field!(to_field3(MyStruct.field3:i32))
    }

    #[test]
    fn test_field_offset() {
        let offset_field1_meth1 = unsafe {
            let nullptr = 0 as * const MyStruct;
            let fieldptr: * const i32 = &((*nullptr).field1);
            fieldptr.to_uint()
        };
        let offset_field1_meth2 = MyStruct::field1_offset();
        assert_eq!(offset_field1_meth1, offset_field1_meth2);
        assert_eq!(0, offset_field1_meth2);
        assert_eq!(4, MyStruct::field2_offset());
        assert_eq!(8, MyStruct::field3_offset());
    }

    #[test]
    fn test_from_field() {
        let m = MyStruct { field1: 0, field2: 0, field3: 0 };
        let m1: * const MyStruct = &m;
        let m2_meth1: * const MyStruct =
            MyStruct::from_field1_meth1(&m.field1);
        assert_eq!(m2_meth1, m1);
        assert_eq!(
            m1, MyStruct::from_field1_meth2(&m.field1) as * const MyStruct);
        assert_eq!(
            m1, MyStruct::from_field2(&m.field2) as * const MyStruct);
        assert_eq!(
            m1, MyStruct::from_field3(&m.field3) as * const MyStruct);
    }
}
<commit_msg>updated to current rust.<commit_after>// offsetof()-like operation. Will become obsolete when-and-if offsetof() is
// implemented in the core language.
pub macro_rules! field_offset {
    ($container:ty : $field:ident) => (unsafe {
        let nullptr = 0 as * const $container;
        let fieldptr: * const _ = &((*nullptr).$field);
        fieldptr as usize
    })
}

#[cfg(test)]
pub mod test {
    pub struct MyStruct {
        field1: i32,
        field2: i32,
        field3: i32,
    }

    impl MyStruct {
        pub fn field1_offset() -> usize {
            field_offset!(MyStruct:field1)
        }
        pub fn field2_offset() -> usize {
            field_offset!(MyStruct:field2)
        }
        pub fn field3_offset() -> usize {
            field_offset!(MyStruct:field3)
        }
    }

    #[test]
    fn test_field_offset() {
        let offset_field1_meth1 = unsafe {
            let nullptr = 0 as * const MyStruct;
            let fieldptr: * const _ = &((*nullptr).field1);
            fieldptr as usize
        };
        let offset_field1_meth2 = MyStruct::field1_offset();
        assert_eq!(offset_field1_meth1, offset_field1_meth2);
        assert_eq!(0, offset_field1_meth2);
        assert_eq!(4, MyStruct::field2_offset());
        assert_eq!(8, MyStruct::field3_offset());
    }
}
<|endoftext|>