<commit_before>extern crate cgmath;
extern crate froggy;
#[macro_use]
extern crate gfx;
extern crate winit;
// OpenGL
#[cfg(feature = "opengl")]
extern crate gfx_device_gl as back;
#[cfg(feature = "opengl")]
extern crate gfx_window_glutin;
#[cfg(feature = "opengl")]
extern crate glutin;

use cgmath::prelude::*;
use cgmath::Transform as Transform_;
use gfx::traits::{Device, FactoryExt};
use std::ops;
use std::sync::mpsc;

pub type Position = cgmath::Point3<f32>;
pub type Normal = cgmath::Vector3<f32>;
pub type Orientation = cgmath::Quaternion<f32>;
pub type Transform = cgmath::Decomposed<Normal, Orientation>;
pub type ColorFormat = gfx::format::Srgba8;
pub type DepthFormat = gfx::format::DepthStencil;
type SceneId = usize;

gfx_vertex_struct!(Vertex {
    pos: [f32; 4] = "a_Position",
});

gfx_pipeline!(pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    mx_vp: gfx::Global<[[f32; 4]; 4]> = "u_ViewProj",
    mx_world: gfx::Global<[[f32; 4]; 4]> = "u_World",
    color: gfx::Global<[f32; 4]> = "u_Color",
    out_color: gfx::RenderTarget<ColorFormat> = "Target0",
});

const LINE_VS: &'static [u8] = b"
    #version 150 core
    in vec4 a_Position;
    uniform mat4 u_ViewProj;
    uniform mat4 u_World;
    void main() {
        gl_Position = u_ViewProj * u_World * a_Position;
    }
";
const LINE_FS: &'static [u8] = b"
    #version 150 core
    uniform vec4 u_Color;
    void main() {
        gl_FragColor = u_Color;
    }
";

pub struct Factory {
    graphics: back::Factory,
    scene_id: SceneId,
}

pub struct Renderer {
    device: back::Device,
    encoder: gfx::Encoder<back::Resources, back::CommandBuffer>,
    out_color: gfx::handle::RenderTargetView<back::Resources, ColorFormat>,
    out_depth: gfx::handle::DepthStencilView<back::Resources, DepthFormat>,
    pso_line: gfx::PipelineState<back::Resources, pipe::Meta>,
    size: (u32, u32),
    #[cfg(feature = "opengl")]
    window: glutin::Window,
}

#[cfg(feature = "opengl")]
impl Renderer {
    pub fn new(builder: glutin::WindowBuilder, event_loop: &glutin::EventsLoop)
               -> (Renderer, Factory) {
        let (window, device, mut gl_factory, color, depth) =
            gfx_window_glutin::init(builder, event_loop);
        let renderer = Renderer {
            device: device,
            encoder: gl_factory.create_command_buffer().into(),
            out_color: color,
            out_depth: depth,
            pso_line: {
                let prog = gl_factory.link_program(LINE_VS, LINE_FS).unwrap();
                let rast = gfx::state::Rasterizer::new_fill();
                gl_factory.create_pipeline_from_program(&prog,
                    gfx::Primitive::LineStrip, rast, pipe::new()
                ).unwrap()
            },
            size: window.get_inner_size_pixels().unwrap(),
            window: window,
        };
        let factory = Factory {
            graphics: gl_factory,
            scene_id: 0,
        };
        (renderer, factory)
    }

    pub fn resize(&mut self) {
        self.size = self.window.get_inner_size_pixels().unwrap();
        gfx_window_glutin::update_views(&self.window, &mut self.out_color, &mut self.out_depth);
    }
}

pub trait Camera {
    fn to_view_proj(&self) -> cgmath::Matrix4<f32>;
}

pub struct PerspectiveCamera {
    pub projection: cgmath::PerspectiveFov<f32>,
    pub position: Position,
    pub orientation: Orientation,
}

impl PerspectiveCamera {
    pub fn new(fov: f32, aspect: f32, near: f32, far: f32) -> PerspectiveCamera {
        PerspectiveCamera {
            projection: cgmath::PerspectiveFov {
                fovy: cgmath::Deg(fov).into(),
                aspect: aspect,
                near: near,
                far: far,
            },
            position: Position::origin(),
            orientation: Orientation::one(),
        }
    }

    pub fn look_at(&mut self, target: cgmath::Point3<f32>) {
        let dir = (self.position - target).normalize();
        let z = cgmath::Vector3::unit_z();
        let up = if dir.dot(z).abs() < 0.99 { z } else {
            cgmath::Vector3::unit_y()
        };
        self.orientation = Orientation::look_at(dir, up);
    }
}

impl Camera for PerspectiveCamera {
    fn to_view_proj(&self) -> cgmath::Matrix4<f32> {
        let mx_proj = cgmath::perspective(self.projection.fovy,
            self.projection.aspect, self.projection.near, self.projection.far);
        let transform = cgmath::Decomposed {
            disp: self.position.to_vec(),
            rot: self.orientation,
            scale: 1.0,
        };

        let mx_view = cgmath::Matrix4::from(transform.inverse_transform().unwrap());
        mx_proj * mx_view
    }
}

#[derive(Clone)]
pub struct Geometry {
    pub vertices: Vec<Position>,
    pub normals: Vec<Normal>,
    pub faces: Vec<[u16; 3]>,
    pub is_dynamic: bool,
}

impl Geometry {
    pub fn new() -> Geometry {
        Geometry {
            vertices: Vec::new(),
            normals: Vec::new(),
            faces: Vec::new(),
            is_dynamic: false,
        }
    }
    pub fn from_vertices(verts: Vec<Position>) -> Geometry {
        Geometry {
            vertices: verts,
            .. Geometry::new()
        }
    }
}

enum Message {
    SetTransform(froggy::WeakPointer<Node>, Transform),
    SetMaterial(froggy::WeakPointer<Visual>, Material),
    //Delete,
}

type NodePtr = froggy::Pointer<Node>;
type VisualPtr = froggy::Pointer<Visual>;

pub type Color = u32;

#[derive(Clone)]
pub enum Material {
    LineBasic { color: Color },
}

struct SceneLink<V> {
    id: SceneId,
    node: NodePtr,
    visual: V,
    tx: mpsc::Sender<Message>,
}

pub struct Object {
    transform: Transform,
    scenes: Vec<SceneLink<()>>,
}

pub struct VisualObject {
    visible: bool,
    transform: Transform,
    material: Material,
    gpu_data: GpuData,
    scenes: Vec<SceneLink<VisualPtr>>,
}

macro_rules! def_proxy {
    ($name:ident<$visual:ty, $target:ty> = $message:ident($key:ident)) => {
        pub struct $name<'a> {
            value: &'a mut $target,
            links: &'a [SceneLink<$visual>],
        }

        impl<'a> ops::Deref for $name<'a> {
            type Target = $target;
            fn deref(&self) -> &Self::Target {
                self.value
            }
        }

        impl<'a> ops::DerefMut for $name<'a> {
            fn deref_mut(&mut self) -> &mut Self::Target {
                self.value
            }
        }

        impl<'a> Drop for $name<'a> {
            fn drop(&mut self) {
                for link in self.links {
                    let msg = Message::$message(link.$key.downgrade(), self.value.clone());
                    let _ = link.tx.send(msg);
                }
            }
        }
    }
}

def_proxy!(TransformProxy<(), Transform> = SetTransform(node));
def_proxy!(TransformProxyVisual<VisualPtr, Transform> = SetTransform(node));
def_proxy!(MaterialProxy<VisualPtr, Material> = SetMaterial(visual));

impl Object {
    fn new() -> Self {
        Object {
            transform: Transform::one(),
            scenes: Vec::with_capacity(1),
        }
    }

    fn get_scene(&self, id: SceneId) -> Option<&SceneLink<()>> {
        self.scenes.iter().find(|link| link.id == id)
    }

    pub fn transform(&self) -> &Transform {
        &self.transform
    }

    pub fn transform_mut(&mut self) -> TransformProxy {
        TransformProxy {
            value: &mut self.transform,
            links: &self.scenes,
        }
    }

    pub fn attach(&mut self, scene: &mut Scene, group: Option<&Group>) {
        assert!(self.get_scene(scene.unique_id).is_none(),
            "Object is already in the scene");
        let node_ptr = scene.make_node(self.transform.clone(), group);
        self.scenes.push(SceneLink {
            id: scene.unique_id,
            node: node_ptr,
            visual: (),
            tx: scene.message_tx.clone(),
        });
    }
}

impl VisualObject {
    fn new(material: Material, gpu_data: GpuData) -> Self {
        VisualObject {
            visible: true,
            transform: Transform::one(),
            material: material,
            gpu_data: gpu_data,
            scenes: Vec::with_capacity(1),
        }
    }

    fn get_scene(&self, id: SceneId) -> Option<&SceneLink<VisualPtr>> {
        self.scenes.iter().find(|link| link.id == id)
    }

    pub fn transform(&self) -> &Transform {
        &self.transform
    }

    pub fn transform_mut(&mut self) -> TransformProxyVisual {
        TransformProxyVisual {
            value: &mut self.transform,
            links: &self.scenes,
        }
    }

    pub fn material(&self) -> &Material {
        &self.material
    }

    pub fn material_mut(&mut self) -> MaterialProxy {
        MaterialProxy {
            value: &mut self.material,
            links: &self.scenes,
        }
    }

    pub fn attach(&mut self, scene: &mut Scene, group: Option<&Group>) {
        assert!(self.get_scene(scene.unique_id).is_none(),
            "VisualObject is already in the scene");
        let node_ptr = scene.make_node(self.transform.clone(), group);
        let visual_ptr = scene.visuals.create(Visual {
            material: self.material.clone(),
            gpu_data: self.gpu_data.clone(),
            node: node_ptr.clone(),
        });
        self.scenes.push(SceneLink {
            id: scene.unique_id,
            node: node_ptr,
            visual: visual_ptr,
            tx: scene.message_tx.clone(),
        });
    }
}

pub struct Line {
    object: VisualObject,
    _geometry: Option<Geometry>,
}

impl ops::Deref for Line {
    type Target = VisualObject;
    fn deref(&self) -> &Self::Target {
        &self.object
    }
}

impl ops::DerefMut for Line {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.object
    }
}

pub struct Group {
    object: Object,
}

impl ops::Deref for Group {
    type Target = Object;
    fn deref(&self) -> &Self::Target {
        &self.object
    }
}

impl ops::DerefMut for Group {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.object
    }
}

struct Node {
    local: Transform,
    world: Transform,
    parent: Option<NodePtr>,
}

#[derive(Clone)]
struct GpuData {
    slice: gfx::Slice<back::Resources>,
    vertices: gfx::handle::Buffer<back::Resources, Vertex>,
}

struct Visual {
    material: Material,
    gpu_data: GpuData,
    node: NodePtr,
}

pub struct Scene {
    nodes: froggy::Storage<Node>,
    visuals: froggy::Storage<Visual>,
    unique_id: SceneId,
    message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Scene {
    fn make_node(&mut self, transform: Transform, group: Option<&Group>) -> NodePtr {
        let parent = group.map(|g| {
            g.get_scene(self.unique_id)
             .expect("Parent group is not in the scene")
             .node.clone()
        });
        self.nodes.create(Node {
            local: transform,
            world: Transform::one(),
            parent: parent,
        })
    }

    pub fn process_messages(&mut self) {
        while let Ok(message) = self.message_rx.try_recv() {
            match message {
                Message::SetTransform(pnode, transform) => {
                    if let Ok(ref ptr) = pnode.upgrade() {
                        self.nodes[ptr].local = transform;
                    }
                }
                Message::SetMaterial(pvisual, material) => {
                    if let Ok(ref ptr) = pvisual.upgrade() {
                        self.visuals[ptr].material = material;
                    }
                }
            }
        }
    }

    pub fn compute_transforms(&mut self) {
        let mut cursor = self.nodes.cursor();
        while let Some(mut item) = cursor.next() {
            item.world = match item.parent {
                Some(ref parent) => item.look_back(parent).unwrap().world.concat(&item.local),
                None => item.local,
            };
        }
    }

    pub fn update(&mut self) {
        self.process_messages();
        self.compute_transforms();
    }
}

impl Factory {
    pub fn scene(&mut self) -> Scene {
        self.scene_id += 1;
        let (tx, rx) = mpsc::channel();
        Scene {
            nodes: froggy::Storage::new(),
            visuals: froggy::Storage::new(),
            unique_id: self.scene_id,
            message_tx: tx,
            message_rx: rx,
        }
    }

    pub fn group(&mut self) -> Group {
        Group {
            object: Object::new(),
        }
    }

    pub fn line(&mut self, geom: Geometry, mat: Material) -> Line {
        let vertices: Vec<_> = geom.vertices.iter().map(|v| Vertex {
            pos: [v.x, v.y, v.z, 1.0],
        }).collect();
        //TODO: dynamic geometry
        let (vbuf, slice) = self.graphics.create_vertex_buffer_with_slice(&vertices, ());
        Line {
            object: VisualObject::new(mat, GpuData {
                slice: slice,
                vertices: vbuf,
            }),
            _geometry: if geom.is_dynamic { Some(geom) } else { None },
        }
    }

    // pub fn update(&self, ) //TODO: update dynamic geometry
}

impl Renderer {
    pub fn get_aspect(&self) -> f32 {
        self.size.0 as f32 / self.size.1 as f32
    }

    pub fn render<C: Camera>(&mut self, scene: &Scene, cam: &C) {
        self.device.cleanup();
        self.encoder.clear(&self.out_color, [0.0, 0.0, 0.0, 1.0]);
        self.encoder.clear_depth(&self.out_depth, 1.0);

        let mx_vp = cam.to_view_proj();
        for visual in &scene.visuals {
            let color = match visual.material {
                Material::LineBasic { color } => {
                    [((color>>16)&0xFF) as f32 / 255.0,
                     ((color>>8) &0xFF) as f32 / 255.0,
                     (color&0xFF) as f32 / 255.0,
                     1.0]
                },
            };
            let mx_world = cgmath::Matrix4::from(scene.nodes[&visual.node].world);
            let data = pipe::Data {
                vbuf: visual.gpu_data.vertices.clone(),
                mx_vp: mx_vp.into(),
                mx_world: mx_world.into(),
                color: color,
                out_color: self.out_color.clone(),
            };
            self.encoder.draw(&visual.gpu_data.slice, &self.pso_line, &data);
        }

        self.encoder.flush(&mut self.device);
        self.window.swap_buffers().unwrap();
    }
}
<commit_msg>Removed get_scene, macro-generated object derefs<commit_after>extern crate cgmath;
extern crate froggy;
#[macro_use]
extern crate gfx;
extern crate winit;
// OpenGL
#[cfg(feature = "opengl")]
extern crate gfx_device_gl as back;
#[cfg(feature = "opengl")]
extern crate gfx_window_glutin;
#[cfg(feature = "opengl")]
extern crate glutin;

use cgmath::prelude::*;
use cgmath::Transform as Transform_;
use gfx::traits::{Device, FactoryExt};
use std::ops;
use std::sync::mpsc;

pub type Position = cgmath::Point3<f32>;
pub type Normal = cgmath::Vector3<f32>;
pub type Orientation = cgmath::Quaternion<f32>;
pub type Transform = cgmath::Decomposed<Normal, Orientation>;
pub type ColorFormat = gfx::format::Srgba8;
pub type DepthFormat = gfx::format::DepthStencil;
type SceneId = usize;

gfx_vertex_struct!(Vertex {
    pos: [f32; 4] = "a_Position",
});

gfx_pipeline!(pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    mx_vp: gfx::Global<[[f32; 4]; 4]> = "u_ViewProj",
    mx_world: gfx::Global<[[f32; 4]; 4]> = "u_World",
    color: gfx::Global<[f32; 4]> = "u_Color",
    out_color: gfx::RenderTarget<ColorFormat> = "Target0",
});

const LINE_VS: &'static [u8] = b"
    #version 150 core
    in vec4 a_Position;
    uniform mat4 u_ViewProj;
    uniform mat4 u_World;
    void main() {
        gl_Position = u_ViewProj * u_World * a_Position;
    }
";
const LINE_FS: &'static [u8] = b"
    #version 150 core
    uniform vec4 u_Color;
    void main() {
        gl_FragColor = u_Color;
    }
";

pub struct Factory {
    graphics: back::Factory,
    scene_id: SceneId,
}

pub struct Renderer {
    device: back::Device,
    encoder: gfx::Encoder<back::Resources, back::CommandBuffer>,
    out_color: gfx::handle::RenderTargetView<back::Resources, ColorFormat>,
    out_depth: gfx::handle::DepthStencilView<back::Resources, DepthFormat>,
    pso_line: gfx::PipelineState<back::Resources, pipe::Meta>,
    size: (u32, u32),
    #[cfg(feature = "opengl")]
    window: glutin::Window,
}

#[cfg(feature = "opengl")]
impl Renderer {
    pub fn new(builder: glutin::WindowBuilder, event_loop: &glutin::EventsLoop)
               -> (Renderer, Factory) {
        let (window, device, mut gl_factory, color, depth) =
            gfx_window_glutin::init(builder, event_loop);
        let renderer = Renderer {
            device: device,
            encoder: gl_factory.create_command_buffer().into(),
            out_color: color,
            out_depth: depth,
            pso_line: {
                let prog = gl_factory.link_program(LINE_VS, LINE_FS).unwrap();
                let rast = gfx::state::Rasterizer::new_fill();
                gl_factory.create_pipeline_from_program(&prog,
                    gfx::Primitive::LineStrip, rast, pipe::new()
                ).unwrap()
            },
            size: window.get_inner_size_pixels().unwrap(),
            window: window,
        };
        let factory = Factory {
            graphics: gl_factory,
            scene_id: 0,
        };
        (renderer, factory)
    }

    pub fn resize(&mut self) {
        self.size = self.window.get_inner_size_pixels().unwrap();
        gfx_window_glutin::update_views(&self.window, &mut self.out_color, &mut self.out_depth);
    }
}

pub trait Camera {
    fn to_view_proj(&self) -> cgmath::Matrix4<f32>;
}

pub struct PerspectiveCamera {
    pub projection: cgmath::PerspectiveFov<f32>,
    pub position: Position,
    pub orientation: Orientation,
}

impl PerspectiveCamera {
    pub fn new(fov: f32, aspect: f32, near: f32, far: f32) -> PerspectiveCamera {
        PerspectiveCamera {
            projection: cgmath::PerspectiveFov {
                fovy: cgmath::Deg(fov).into(),
                aspect: aspect,
                near: near,
                far: far,
            },
            position: Position::origin(),
            orientation: Orientation::one(),
        }
    }

    pub fn look_at(&mut self, target: cgmath::Point3<f32>) {
        let dir = (self.position - target).normalize();
        let z = cgmath::Vector3::unit_z();
        let up = if dir.dot(z).abs() < 0.99 { z } else {
            cgmath::Vector3::unit_y()
        };
        self.orientation = Orientation::look_at(dir, up);
    }
}

impl Camera for PerspectiveCamera {
    fn to_view_proj(&self) -> cgmath::Matrix4<f32> {
        let mx_proj = cgmath::perspective(self.projection.fovy,
            self.projection.aspect, self.projection.near, self.projection.far);
        let transform = cgmath::Decomposed {
            disp: self.position.to_vec(),
            rot: self.orientation,
            scale: 1.0,
        };

        let mx_view = cgmath::Matrix4::from(transform.inverse_transform().unwrap());
        mx_proj * mx_view
    }
}

#[derive(Clone)]
pub struct Geometry {
    pub vertices: Vec<Position>,
    pub normals: Vec<Normal>,
    pub faces: Vec<[u16; 3]>,
    pub is_dynamic: bool,
}

impl Geometry {
    pub fn new() -> Geometry {
        Geometry {
            vertices: Vec::new(),
            normals: Vec::new(),
            faces: Vec::new(),
            is_dynamic: false,
        }
    }
    pub fn from_vertices(verts: Vec<Position>) -> Geometry {
        Geometry {
            vertices: verts,
            .. Geometry::new()
        }
    }
}

enum Message {
    SetTransform(froggy::WeakPointer<Node>, Transform),
    SetMaterial(froggy::WeakPointer<Visual>, Material),
    //Delete,
}

type NodePtr = froggy::Pointer<Node>;
type VisualPtr = froggy::Pointer<Visual>;

pub type Color = u32;

#[derive(Clone)]
pub enum Material {
    LineBasic { color: Color },
}

struct SceneLink<V> {
    id: SceneId,
    node: NodePtr,
    visual: V,
    tx: mpsc::Sender<Message>,
}

pub struct Object {
    transform: Transform,
    scenes: Vec<SceneLink<()>>,
}

pub struct VisualObject {
    visible: bool,
    transform: Transform,
    material: Material,
    gpu_data: GpuData,
    scenes: Vec<SceneLink<VisualPtr>>,
}

macro_rules! def_proxy {
    ($name:ident<$visual:ty, $target:ty> = $message:ident($key:ident)) => {
        pub struct $name<'a> {
            value: &'a mut $target,
            links: &'a [SceneLink<$visual>],
        }

        impl<'a> ops::Deref for $name<'a> {
            type Target = $target;
            fn deref(&self) -> &Self::Target {
                self.value
            }
        }

        impl<'a> ops::DerefMut for $name<'a> {
            fn deref_mut(&mut self) -> &mut Self::Target {
                self.value
            }
        }

        impl<'a> Drop for $name<'a> {
            fn drop(&mut self) {
                for link in self.links {
                    let msg = Message::$message(link.$key.downgrade(), self.value.clone());
                    let _ = link.tx.send(msg);
                }
            }
        }
    }
}

def_proxy!(TransformProxy<(), Transform> = SetTransform(node));
def_proxy!(TransformProxyVisual<VisualPtr, Transform> = SetTransform(node));
def_proxy!(MaterialProxy<VisualPtr, Material> = SetMaterial(visual));

impl Object {
    fn new() -> Self {
        Object {
            transform: Transform::one(),
            scenes: Vec::with_capacity(1),
        }
    }

    pub fn transform(&self) -> &Transform {
        &self.transform
    }

    pub fn transform_mut(&mut self) -> TransformProxy {
        TransformProxy {
            value: &mut self.transform,
            links: &self.scenes,
        }
    }

    pub fn attach(&mut self, scene: &mut Scene, group: Option<&Group>) {
        assert!(!self.scenes.iter().any(|link| link.id == scene.unique_id),
            "Object is already in the scene");
        let node_ptr = scene.make_node(self.transform.clone(), group);
        self.scenes.push(SceneLink {
            id: scene.unique_id,
            node: node_ptr,
            visual: (),
            tx: scene.message_tx.clone(),
        });
    }
}

impl VisualObject {
    fn new(material: Material, gpu_data: GpuData) -> Self {
        VisualObject {
            visible: true,
            transform: Transform::one(),
            material: material,
            gpu_data: gpu_data,
            scenes: Vec::with_capacity(1),
        }
    }

    pub fn transform(&self) -> &Transform {
        &self.transform
    }

    pub fn transform_mut(&mut self) -> TransformProxyVisual {
        TransformProxyVisual {
            value: &mut self.transform,
            links: &self.scenes,
        }
    }

    pub fn material(&self) -> &Material {
        &self.material
    }

    pub fn material_mut(&mut self) -> MaterialProxy {
        MaterialProxy {
            value: &mut self.material,
            links: &self.scenes,
        }
    }

    pub fn attach(&mut self, scene: &mut Scene, group: Option<&Group>) {
        assert!(!self.scenes.iter().any(|link| link.id == scene.unique_id),
            "VisualObject is already in the scene");
        let node_ptr = scene.make_node(self.transform.clone(), group);
        let visual_ptr = scene.visuals.create(Visual {
            material: self.material.clone(),
            gpu_data: self.gpu_data.clone(),
            node: node_ptr.clone(),
        });
        self.scenes.push(SceneLink {
            id: scene.unique_id,
            node: node_ptr,
            visual: visual_ptr,
            tx: scene.message_tx.clone(),
        });
    }
}

pub struct Group {
    object: Object,
}

pub struct Line {
    object: VisualObject,
    _geometry: Option<Geometry>,
}

macro_rules! deref {
    ($name:ty = $object:ty) => {
        impl ops::Deref for $name {
            type Target = $object;
            fn deref(&self) -> &Self::Target {
                &self.object
            }
        }

        impl ops::DerefMut for $name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.object
            }
        }
    }
}

deref!(Group = Object);
deref!(Line = VisualObject);

struct Node {
    local: Transform,
    world: Transform,
    parent: Option<NodePtr>,
}

#[derive(Clone)]
struct GpuData {
    slice: gfx::Slice<back::Resources>,
    vertices: gfx::handle::Buffer<back::Resources, Vertex>,
}

struct Visual {
    material: Material,
    gpu_data: GpuData,
    node: NodePtr,
}

pub struct Scene {
    nodes: froggy::Storage<Node>,
    visuals: froggy::Storage<Visual>,
    unique_id: SceneId,
    message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Scene {
    fn make_node(&mut self, transform: Transform, group: Option<&Group>) -> NodePtr {
        let parent = group.map(|g| {
            g.scenes.iter().find(|link| link.id == self.unique_id)
             .expect("Parent group is not in the scene")
             .node.clone()
        });
        self.nodes.create(Node {
            local: transform,
            world: Transform::one(),
            parent: parent,
        })
    }

    pub fn process_messages(&mut self) {
        while let Ok(message) = self.message_rx.try_recv() {
            match message {
                Message::SetTransform(pnode, transform) => {
                    if let Ok(ref ptr) = pnode.upgrade() {
                        self.nodes[ptr].local = transform;
                    }
                }
                Message::SetMaterial(pvisual, material) => {
                    if let Ok(ref ptr) = pvisual.upgrade() {
                        self.visuals[ptr].material = material;
                    }
                }
            }
        }
    }

    pub fn compute_transforms(&mut self) {
        let mut cursor = self.nodes.cursor();
        while let Some(mut item) = cursor.next() {
            item.world = match item.parent {
                Some(ref parent) => item.look_back(parent).unwrap().world.concat(&item.local),
                None => item.local,
            };
        }
    }

    pub fn update(&mut self) {
        self.process_messages();
        self.compute_transforms();
    }
}

impl Factory {
    pub fn scene(&mut self) -> Scene {
        self.scene_id += 1;
        let (tx, rx) = mpsc::channel();
        Scene {
            nodes: froggy::Storage::new(),
            visuals: froggy::Storage::new(),
            unique_id: self.scene_id,
            message_tx: tx,
            message_rx: rx,
        }
    }

    pub fn group(&mut self) -> Group {
        Group {
            object: Object::new(),
        }
    }

    pub fn line(&mut self, geom: Geometry, mat: Material) -> Line {
        let vertices: Vec<_> = geom.vertices.iter().map(|v| Vertex {
            pos: [v.x, v.y, v.z, 1.0],
        }).collect();
        //TODO: dynamic geometry
        let (vbuf, slice) = self.graphics.create_vertex_buffer_with_slice(&vertices, ());
        Line {
            object: VisualObject::new(mat, GpuData {
                slice: slice,
                vertices: vbuf,
            }),
            _geometry: if geom.is_dynamic { Some(geom) } else { None },
        }
    }

    // pub fn update(&self, ) //TODO: update dynamic geometry
}

impl Renderer {
    pub fn get_aspect(&self) -> f32 {
        self.size.0 as f32 / self.size.1 as f32
    }

    pub fn render<C: Camera>(&mut self, scene: &Scene, cam: &C) {
        self.device.cleanup();
        self.encoder.clear(&self.out_color, [0.0, 0.0, 0.0, 1.0]);
        self.encoder.clear_depth(&self.out_depth, 1.0);

        let mx_vp = cam.to_view_proj();
        for visual in &scene.visuals {
            let color = match visual.material {
                Material::LineBasic { color } => {
                    [((color>>16)&0xFF) as f32 / 255.0,
                     ((color>>8) &0xFF) as f32 / 255.0,
                     (color&0xFF) as f32 / 255.0,
                     1.0]
                },
            };
            let mx_world = cgmath::Matrix4::from(scene.nodes[&visual.node].world);
            let data = pipe::Data {
                vbuf: visual.gpu_data.vertices.clone(),
                mx_vp: mx_vp.into(),
                mx_world: mx_world.into(),
                color: color,
                out_color: self.out_color.clone(),
            };
            self.encoder.draw(&visual.gpu_data.slice, &self.pso_line, &data);
        }

        self.encoder.flush(&mut self.device);
        self.window.swap_buffers().unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
             -> Result<Response, Box<Show + 'static>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show + 'static>>)
                  -> Result<Response, Box<Show + 'static>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(&*e).to_string().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
            Err(box "Nope".to_string() as Box<Show + 'static>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show + 'a
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_string())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
             -> Result<Response, Box<Show + 'static>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show + 'static>>)
                  -> Result<Response, Box<Show + 'static>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(&*e).to_string().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show + 'static>> {
            Err(box "Nope".to_string() as Box<Show + 'static>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show + 'static>>)
                     -> Result<Response, Box<Show + 'static>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a (Show + 'a),
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_string())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod mul;
pub use mul::*;

pub mod sdiv;
pub use sdiv::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<commit_msg>updated to lastest rust nightly<commit_after>#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod mul;
pub use mul::*;

pub mod sdiv;
pub use sdiv::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<|endoftext|>


<commit_before>//! [![GitHub time-rs/time](https://img.shields.io/badge/GitHub-time--rs%2Ftime-9b88bb?logo=github&style=for-the-badge)](https://github.com/time-rs/time)
//! ![license MIT or Apache-2.0](https://img.shields.io/badge/license-MIT%20or%20Apache--2.0-779a6b?style=for-the-badge)
//! [![minimum rustc 1.40.0](https://img.shields.io/badge/minimum%20rustc-1.40.0-c18170?logo=rust&style=for-the-badge)](https://www.whatrustisit.com)
//!
//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as
//! shown [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html).
//! Features are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item
//! definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!   [`Instant`] is the primary item that requires this feature, though some
//!   others methods may rely on [`Instant`] internally.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically
//!   allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and
//!   intuitive syntax.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's
//!   UTC offset.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types.
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `rand`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].

#![cfg_attr(__time_03_docs, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    broken_intra_doc_links,
    clippy::all,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_code,
    unused_extern_crates
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::pedantic,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unwrap_used,
    clippy::use_debug,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(
    clippy::cast_lossless,
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::map_err_ignore,
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
    clippy::redundant_pub_crate,
    clippy::wildcard_imports
)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

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

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        #![allow(trivial_numeric_casts, unused_comparisons)]
        if $value < $start || $value > $end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: $start as i64,
                maximum: $end as i64,
                value: $value as i64,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        #![allow(trivial_numeric_casts, unused_comparisons)]
        if $value < $start || $value > $end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: $start as i64,
                maximum: $end as i64,
                value: $value as i64,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because
/// of this, it is usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}

/// The [`Date`] struct and its associated `impl`s.
mod date;
/// The [`Duration`] struct and its associated `impl`s.
mod duration;
/// Various error types returned by methods in the time crate.
pub mod error;
/// Extension traits.
pub mod ext;
pub mod format_description;
// TODO visibility checks
pub mod formatting;
/// The [`Instant`] struct and its associated `impl`s.
#[cfg(feature = "std")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "std")))]
mod instant;
/// The [`OffsetDateTime`] struct and its associated `impl`s.
mod offset_date_time;
/// The [`PrimitiveDateTime`] struct and its associated `impl`s.
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "quickcheck")))]
mod quickcheck;
#[cfg(feature = "rand")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "rand")))]
mod rand;
#[cfg(feature = "serde")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "serde")))]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
/// The [`Time`] struct and its associated `impl`s.
mod time;
/// The [`UtcOffset`] struct and its associated `impl`s.
mod utc_offset;
pub mod util;
/// Days of the week.
mod weekday;
/// Macros to construct statically known values.
#[cfg(feature = "macros")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "macros")))]
pub mod macros {
    /// Construct a [`Date`](crate::Date) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// Three formats are supported: year-week-weekday, year-ordinal, and
    /// year-month-day.
    ///
    /// ```rust
    /// # use time::{Date, Weekday::*};
    /// # use time_macros::date;
    /// assert_eq!(date!("2020-W01-3"), Date::from_iso_ywd(2020, 1, Wednesday)?);
    /// assert_eq!(date!("2020-001"), Date::from_yo(2020, 1)?);
    /// assert_eq!(date!("2020-01-01"), Date::from_ymd(2020, 1, 1)?);
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::date;
    /// Construct a [`PrimitiveDateTime`] or [`OffsetDateTime`] with a
    /// statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// The syntax accepted by this macro is the same as [`date!`] and
    /// [`time!`], with an optional [`offset!`], all space-separated. If an
    /// [`offset!`] is provided, the resulting value will be an
    /// [`OffsetDateTime`]; otherwise it will be a [`PrimitiveDateTime`].
    ///
    /// [`date!`]: crate::macros::date
    /// [`time!`]: crate::macros::time
    /// [`offset!`]: crate::macros::offset
    /// [`OffsetDateTime`]: crate::OffsetDateTime
    /// [`PrimitiveDateTime`]: crate::PrimitiveDateTime
    pub use time_macros::datetime;
    /// Construct a [`UtcOffset`](crate::UtcOffset) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// A sign and the hour must be provided; minutes and seconds default to zero.
    /// `UTC` (both uppercase and lowercase) is also allowed.
    ///
    /// ```rust
    /// # use time::UtcOffset;
    /// # use time_macros::offset;
    /// assert_eq!(offset!("UTC"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("utc"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("+0"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("+1"), UtcOffset::hours(1)?);
    /// assert_eq!(offset!("-1"), UtcOffset::hours(-1)?);
    /// assert_eq!(offset!("+1:30"), UtcOffset::minutes(90)?);
    /// assert_eq!(offset!("-1:30"), UtcOffset::minutes(-90)?);
    /// assert_eq!(offset!("+1:30:59"), UtcOffset::seconds(5459)?);
    /// assert_eq!(offset!("-1:30:59"), UtcOffset::seconds(-5459)?);
    /// assert_eq!(offset!("+23:59:59"), UtcOffset::seconds(86_399)?);
    /// assert_eq!(offset!("-23:59:59"), UtcOffset::seconds(-86_399)?);
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::offset;
    /// Construct a [`Time`](crate::Time) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// Hours and minutes must be provided, while seconds defaults to zero. AM/PM is
    /// allowed (either uppercase or lowercase). Any number of subsecond digits may
    /// be provided (though any past nine will be discarded).
    ///
    /// All components are validated at compile-time. An error will be raised if any
    /// value is invalid.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time_macros::time;
    /// assert_eq!(time!("0:00"), Time::from_hms(0, 0, 0)?);
    /// assert_eq!(time!("1:02:03"), Time::from_hms(1, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006"),
    ///     Time::from_hms_nano(1, 2, 3, 4_005_006)?
    /// );
    /// assert_eq!(time!("12:00 am"), Time::from_hms(0, 0, 0)?);
    /// assert_eq!(time!("1:02:03 am"), Time::from_hms(1, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006 am"),
    ///     Time::from_hms_nano(1, 2, 3, 4_005_006)?
    /// );
    /// assert_eq!(time!("12:00 pm"), Time::from_hms(12, 0, 0)?);
    /// assert_eq!(time!("1:02:03 pm"), Time::from_hms(13, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006 pm"),
    ///     Time::from_hms_nano(13, 2, 3, 4_005_006)?
    /// );
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::time;
}

pub use crate::time::Time;
pub use date::Date;
pub use duration::Duration;
pub use error::Error;
#[cfg(feature = "std")]
pub use instant::Instant;
pub use offset_date_time::OffsetDateTime;
pub use primitive_date_time::PrimitiveDateTime;
pub use utc_offset::UtcOffset;
pub use weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time
/// crate.
pub type Result<T> = core::result::Result<T, Error>;
<commit_msg>Move lint to avoid warning on 1.40<commit_after>//! [![GitHub time-rs/time](https://img.shields.io/badge/GitHub-time--rs%2Ftime-9b88bb?logo=github&style=for-the-badge)](https://github.com/time-rs/time)
//! ![license MIT or Apache-2.0](https://img.shields.io/badge/license-MIT%20or%20Apache--2.0-779a6b?style=for-the-badge)
//! [![minimum rustc 1.40.0](https://img.shields.io/badge/minimum%20rustc-1.40.0-c18170?logo=rust&style=for-the-badge)](https://www.whatrustisit.com)
//!
//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as
//! shown [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html).
//! Features are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item
//! definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!   [`Instant`] is the primary item that requires this feature, though some
//!   others methods may rely on [`Instant`] internally.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically
//!   allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and
//!   intuitive syntax.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's
//!   UTC offset.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types.
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `rand`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].

#![cfg_attr(__time_03_docs, feature(doc_cfg))]
#![cfg_attr(__time_03_docs, deny(broken_intra_doc_links))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    clippy::all,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_code,
    unused_extern_crates
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::pedantic,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unwrap_used,
    clippy::use_debug,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(
    clippy::cast_lossless,
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::map_err_ignore,
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
    clippy::redundant_pub_crate,
    clippy::wildcard_imports
)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

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

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        #![allow(trivial_numeric_casts, unused_comparisons)]
        if $value < $start || $value > $end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: $start as i64,
                maximum: $end as i64,
                value: $value as i64,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        #![allow(trivial_numeric_casts, unused_comparisons)]
        if $value < $start || $value > $end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: $start as i64,
                maximum: $end as i64,
                value: $value as i64,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because
/// of this, it is usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}

/// The [`Date`] struct and its associated `impl`s.
mod date;
/// The [`Duration`] struct and its associated `impl`s.
mod duration;
/// Various error types returned by methods in the time crate.
pub mod error;
/// Extension traits.
pub mod ext;
pub mod format_description;
// TODO visibility checks
pub mod formatting;
/// The [`Instant`] struct and its associated `impl`s.
#[cfg(feature = "std")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "std")))]
mod instant;
/// The [`OffsetDateTime`] struct and its associated `impl`s.
mod offset_date_time;
/// The [`PrimitiveDateTime`] struct and its associated `impl`s.
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "quickcheck")))]
mod quickcheck;
#[cfg(feature = "rand")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "rand")))]
mod rand;
#[cfg(feature = "serde")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "serde")))]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
/// The [`Time`] struct and its associated `impl`s.
mod time;
/// The [`UtcOffset`] struct and its associated `impl`s.
mod utc_offset;
pub mod util;
/// Days of the week.
mod weekday;
/// Macros to construct statically known values.
#[cfg(feature = "macros")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "macros")))]
pub mod macros {
    /// Construct a [`Date`](crate::Date) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// Three formats are supported: year-week-weekday, year-ordinal, and
    /// year-month-day.
    ///
    /// ```rust
    /// # use time::{Date, Weekday::*};
    /// # use time_macros::date;
    /// assert_eq!(date!("2020-W01-3"), Date::from_iso_ywd(2020, 1, Wednesday)?);
    /// assert_eq!(date!("2020-001"), Date::from_yo(2020, 1)?);
    /// assert_eq!(date!("2020-01-01"), Date::from_ymd(2020, 1, 1)?);
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::date;
    /// Construct a [`PrimitiveDateTime`] or [`OffsetDateTime`] with a
    /// statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// The syntax accepted by this macro is the same as [`date!`] and
    /// [`time!`], with an optional [`offset!`], all space-separated. If an
    /// [`offset!`] is provided, the resulting value will be an
    /// [`OffsetDateTime`]; otherwise it will be a [`PrimitiveDateTime`].
    ///
    /// [`date!`]: crate::macros::date
    /// [`time!`]: crate::macros::time
    /// [`offset!`]: crate::macros::offset
    /// [`OffsetDateTime`]: crate::OffsetDateTime
    /// [`PrimitiveDateTime`]: crate::PrimitiveDateTime
    pub use time_macros::datetime;
    /// Construct a [`UtcOffset`](crate::UtcOffset) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// A sign and the hour must be provided; minutes and seconds default to zero.
    /// `UTC` (both uppercase and lowercase) is also allowed.
    ///
    /// ```rust
    /// # use time::UtcOffset;
    /// # use time_macros::offset;
    /// assert_eq!(offset!("UTC"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("utc"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("+0"), UtcOffset::hours(0)?);
    /// assert_eq!(offset!("+1"), UtcOffset::hours(1)?);
    /// assert_eq!(offset!("-1"), UtcOffset::hours(-1)?);
    /// assert_eq!(offset!("+1:30"), UtcOffset::minutes(90)?);
    /// assert_eq!(offset!("-1:30"), UtcOffset::minutes(-90)?);
    /// assert_eq!(offset!("+1:30:59"), UtcOffset::seconds(5459)?);
    /// assert_eq!(offset!("-1:30:59"), UtcOffset::seconds(-5459)?);
    /// assert_eq!(offset!("+23:59:59"), UtcOffset::seconds(86_399)?);
    /// assert_eq!(offset!("-23:59:59"), UtcOffset::seconds(-86_399)?);
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::offset;
    /// Construct a [`Time`](crate::Time) with a statically known value.
    ///
    /// The resulting expression can be used in `const` or `static` declarations.
    ///
    /// Hours and minutes must be provided, while seconds defaults to zero. AM/PM is
    /// allowed (either uppercase or lowercase). Any number of subsecond digits may
    /// be provided (though any past nine will be discarded).
    ///
    /// All components are validated at compile-time. An error will be raised if any
    /// value is invalid.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time_macros::time;
    /// assert_eq!(time!("0:00"), Time::from_hms(0, 0, 0)?);
    /// assert_eq!(time!("1:02:03"), Time::from_hms(1, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006"),
    ///     Time::from_hms_nano(1, 2, 3, 4_005_006)?
    /// );
    /// assert_eq!(time!("12:00 am"), Time::from_hms(0, 0, 0)?);
    /// assert_eq!(time!("1:02:03 am"), Time::from_hms(1, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006 am"),
    ///     Time::from_hms_nano(1, 2, 3, 4_005_006)?
    /// );
    /// assert_eq!(time!("12:00 pm"), Time::from_hms(12, 0, 0)?);
    /// assert_eq!(time!("1:02:03 pm"), Time::from_hms(13, 2, 3)?);
    /// assert_eq!(
    ///     time!("1:02:03.004_005_006 pm"),
    ///     Time::from_hms_nano(13, 2, 3, 4_005_006)?
    /// );
    /// # Ok::<_, time::Error>(())
    /// ```
    pub use time_macros::time;
}

pub use crate::time::Time;
pub use date::Date;
pub use duration::Duration;
pub use error::Error;
#[cfg(feature = "std")]
pub use instant::Instant;
pub use offset_date_time::OffsetDateTime;
pub use primitive_date_time::PrimitiveDateTime;
pub use utc_offset::UtcOffset;
pub use weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time
/// crate.
pub type Result<T> = core::result::Result<T, Error>;
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://zzeroo.github.io/share/zzeroo-logo.png",
       html_favicon_url = "https://zzeroo.github.io/share/favicon.ico",
html_root_url = "https://zzeroo.com/")]
//! This is an 'hopefully' safe Rust interface for the [libmodbus](http://libmodbus.org/) C library from
//! http://libmodbus.org/.
//!
//! [libmodbus](http://libmodbus.org/) is a library to send/receive data with a device which respects the Modbus
//! protocol.
//! This library contains various backends to communicate over different networks (eg. serial in RTU mode or Ethernet
//! in TCP/IPv6).
//! The http://www.modbus.org site provides documentation about the protocol at http://www.modbus.org/specs.php.
//!
//! libmodbus provides an abstraction of the lower communication layers and offers the same API on all supported
//! platforms.
//!
//! This documentation presents an overview of libmodbus concepts, describes how libmodbus abstracts Modbus
//! communication with
//! different hardware and platforms and provides a reference manual for the functions provided by the libmodbus
//! library.
//!
//! **This project hosts the original libmodbus documentation, used here, as well.**

//! Please have a look at: [libmodbus/libmodbus.html](../libmodbus/libmodbus.html)
//!
//! ## Contexts
//!
//! The Modbus protocol contains many variants (eg. serial RTU or Ehternet TCP), to ease the implementation of a
//! variant, the library was designed to use a backend for each variant.
//!
//! **libmodbus-rs provides traits and matching implementations for these variants.** See
//! [ModbusRTU](trait.ModbusRTU.html) (trait), [Modbus::new_rtu()](struct.Modbus.html#method.new_rtu) (implementation)
//! or [ModbusTCP](trait.ModbusTCP.html) (trait).
//!
//! The backends are also a convenient way to fulfill other requirements (eg. real-time operations). Each backend
//! offers a specific function to create a new modbus_t context.
//! The modbus_t context is an opaque structure containing all necessary information to establish a connection with
//! others Modbus devices according to the selected variant.
//!
//! You can choose the best context for your needs among:
//!
//! * [RTU Context](trait.ModbusRTU.html)
//! * [TCP (IPv4) Context](trait.ModbusTCP.html)
//! * [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//!
//! ### [RTU Context](trait.ModbusRTU.html)
//!
//! The RTU backend (Remote Terminal Unit) is used in serial communication and makes use of a compact, binary
//! representation of the data for protocol communication.
//! The RTU format follows the commands/data with a cyclic redundancy check checksum as an error check mechanism to
//! ensure the reliability of data.
//! Modbus RTU is the most common implementation available for Modbus. A Modbus RTU message must be transmitted
//! continuously without inter-character hesitations
//! (extract from Wikipedia, Modbus, http://en.wikipedia.org/wiki/Modbus (as of Mar. 13, 2011, 20:51 GMT).
//!
//! The Modbus RTU framing calls a slave, a device/service which handle Modbus requests, and a master, a client which
//! send requests. The communication is always initiated by the master.
//!
//! Many Modbus devices can be connected together on the same physical link so before sending a message, you must set
//! the slave (receiver) with modbus_set_slave(3).
//! If you’re running a slave, its slave number will be used to filter received messages.
//!
//! The libmodbus implementation of RTU isn’t time based as stated in original Modbus specification,
//! instead all bytes are sent as fast as possible and a response or an indication is considered complete when all
//! expected characters have been received.
//! This implementation offers very fast communication but you must take care to set a response timeout of slaves less
//! than response timeout of master
//! (ortherwise other slaves may ignore master requests when one of the slave is not responding).
//!
//! * Create a Modbus RTU context
//!     - [`new_rtu()`](struct.Modbus.html#method.new_rtu)
//!
//! * Set the serial mode
//! - [`rtu_get_serial_mode()`](struct.Modbus.html#method.rtu_get_serial_mode),
//! [`rtu_set_serial_mode()`](struct.Modbus.html#method.rtu_set_serial_mode),
//! [`rtu_get_rts()`](struct.Modbus.html#method.rtu_get_rts), [`rtu_set_rts()`](struct.Modbus.html#method.rtu_set_rts),
//! [`rtu_set_custom_rts()`](struct.Modbus.html#method.rtu_set_custom_rts),
//! [`rtu_get_rts_delay()`](struct.Modbus.html#method.rtu_get_rts_delay),
//! [`rtu_set_rts_delay()`](struct.Modbus.html#method.rtu_set_rts_delay)
//!
//! ### [TCP (IPv4) Context](trait.ModbusTCP.html)
//! The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
//!
//! ### [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//! The TCP PI (Protocol Independent) backend implements a Modbus variant used for communications over TCP IPv4 and
//! IPv6 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! Contrary to the TCP IPv4 only backend, the TCP PI backend offers hostname resolution but it consumes about 1Kb of
//! additional memory.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp_pi()`](struct.Modbus.html#method.new_tcp_pi)
//!
//! ### Common
//!
//! Common methods to modify or change the current modbus context. Some of these function are not nessesary in Rust
//! (e.g. because the Drop trait and so on)
//!
//! * Free libmodbus context
//!     - [`free()`](struct.Modbus.html#method.free) **It should normaly not nessesary to call this function.**

//! Memory handling under Rust controlls the [`Drop trait`](https://doc.rust-lang.org/std/ops/trait.Drop.html) in
//! "the book" you find [more information about](https://doc.rust-lang.org/book/ffi.html#destructors).
//! * Set slave ID
//!     - [`set_slave()`](struct.Modbus.html#method.set_slave)
//! * Enable debug mode
//!     - [`set_debug()`](struct.Modbus.html#method.set_debug)
//! * Timeout settings
//! - [`get_byte_timeout()`](struct.Modbus.html#method.get_byte_timeout)
//! [`set_byte_timeout()`](struct.Modbus.html#method.set_byte_timeout)
//! [`get_response_timeout()`](struct.Modbus.html#method.get_response_timeout)
//! [`set_response_timeout()`](struct.Modbus.html#method.set_response_timeout)
//! * Error recovery mod
//!     - [`set_error_recovery()`](struct.Modbus.html#method.set_error_recovery)
//! * Setter/getter of internal socket
//!     - [`set_socket()`](struct.Modbus.html#method.set_socket) [`get_socket()`](struct.Modbus.html#method.get_socket)
//! * Information about header
//!     - [`get_header_length()`](struct.Modbus.html#method.get_header_length)
//!
//! ### Connection
//!
//! ### [`Client`](trait.ModbusClient.html)
//!
//! The Modbus protocol defines different data types and functions to read and write them from/to remote devices.
//! The following functions are used by the clients to send Modbus requests:
//!
//! * Read data
//! - [`read_bits()`](struct.Modbus.html#method.read_bits),
//! [`read_input_bits()`](struct.Modbus.html#method.read_input_bits),
//! [`read_registers()`](struct.Modbus.html#method.read_registers),
//! [`read_input_registers()`](struct.Modbus.html#method.read_input_registers),
//! [`report_slave_id()`](struct.Modbus.html#method.report_slave_id)
//! * Write data
//! - [`write_bit()`](struct.Modbus.html#method.write_bit),
//! [`write_register()`](struct.Modbus.html#method.write_register),
//! [`write_bits()`](struct.Modbus.html#method.write_bits),
//! [`write_registers()`](struct.Modbus.html#method.write_registers)
//! * Write and read data
//!     - [`write_and_read_registers()`](struct.Modbus.html#method.write_and_read_registers)
//! * Raw requests
//! - [`send_raw_request()`](struct.Modbus.html#method.send_raw_request),
//! [`receive_confirmation()`](struct.Modbus.html#method.receive_confirmation)
//! * Reply an exception
//!     - [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! ### [`Server`](trait.ModbusServer.html)
//!
//! The server is waiting for request from clients and must answer when it is concerned by the request.
//!
//! In TCP , you must not use the usual [`connect()`](struct.Modbus.html#method.connect) to establish the connection
//! but a pair of accept/listen calls
//!
//! * [`tcp_listen()`](struct.Modbus.html#method.tcp_listen), [`tcp_accept()`](struct.Modbus.html#method.tcp_accept),
//! [`tcp_pi_listen`()](struct.Modbus.html#method.tcp_pi_listen),
//! [`tcp_pi_accept`()](struct.Modbus.html#method.tcp_pi_accept)
//!
//! then the data can be received with
//!
//! * [`receive()`](struct.Modbus.html#method.receive)
//!
//! and a response can be send with
//!
//! * [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! To handle the mapping of your Modbus data, you must use a [`ModbusMapping`](struct.ModbusMapping.html) struct:
//! [`ModbusMapping::new()`](struct.ModbusMapping.html#method.new)
//!

// `error_chain!` can recurse deeply(3)
#![recursion_limit = "1024"]

extern crate libc;
extern crate libmodbus_sys;
#[macro_use]
extern crate error_chain;

mod modbus_client;
mod modbus_mapping;
mod modbus_rtu;
mod modbus_server;
mod modbus_tcp_pi;
mod modbus_tcp;
mod modbus;
pub mod errors;

pub use self::modbus_client::ModbusClient;
pub use self::modbus_mapping::ModbusMapping;
pub use self::modbus_rtu::{ModbusRTU, RequestToSendMode, SerialMode};
pub use self::modbus_server::ModbusServer;
pub use self::modbus_tcp_pi::ModbusTCPPI;
pub use self::modbus_tcp::ModbusTCP;
pub use self::modbus::{Modbus, Timeout, ErrorRecoveryMode, Exception, FunctionCode};
pub use self::modbus::{set_bits_from_byte, set_bits_from_bytes, get_byte_from_bits, get_float_abcd, set_float_abcd,
                       get_float_badc, set_float_badc, get_float_cdab, set_float_cdab, get_float_dcba, set_float_dcba};
<commit_msg>Some more typos fixed<commit_after>#![doc(html_logo_url = "https://zzeroo.github.io/share/zzeroo-logo.png",
       html_favicon_url = "https://zzeroo.github.io/share/favicon.ico",
html_root_url = "https://zzeroo.com/")]
//! This is an 'hopefully' safe Rust interface for the [libmodbus](http://libmodbus.org/) C library from
//! http://libmodbus.org/.
//!
//! [libmodbus](http://libmodbus.org/) is a library to send/receive data with a device which respects the Modbus
//! protocol.
//! This library contains various backends to communicate over different networks (eg. serial in RTU mode or Ethernet
//! in TCP/IPv6).
//! The http://www.modbus.org site provides documentation about the protocol at http://www.modbus.org/specs.php.
//!
//! libmodbus provides an abstraction of the lower communication layers and offers the same API on all supported
//! platforms.
//!
//! This documentation presents an overview of libmodbus concepts, describes how libmodbus abstracts Modbus
//! communication with
//! different hardware and platforms and provides a reference manual for the functions provided by the libmodbus
//! library.
//!
//! **This project hosts the original libmodbus documentation, used here, as well.**

//! Please have a look at: [libmodbus/libmodbus.html](../libmodbus/libmodbus.html)
//!
//! ## Contexts
//!
//! The Modbus protocol contains many variants (eg. serial RTU or Ehternet TCP), to ease the implementation of a
//! variant, the library was designed to use a backend for each variant.
//!
//! **libmodbus-rs provides traits and matching implementations for these variants.** See
//! [ModbusRTU](trait.ModbusRTU.html) (trait), [Modbus::new_rtu()](struct.Modbus.html#method.new_rtu) (implementation)
//! or [ModbusTCP](trait.ModbusTCP.html) (trait).
//!
//! The backends are also a convenient way to fulfill other requirements (eg. real-time operations). Each backend
//! offers a specific function to create a new modbus_t context.
//! The modbus_t context is an opaque structure containing all necessary information to establish a connection with
//! others Modbus devices according to the selected variant.
//!
//! You can choose the best context for your needs among:
//!
//! * [RTU Context](trait.ModbusRTU.html)
//! * [TCP (IPv4) Context](trait.ModbusTCP.html)
//! * [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//!
//! ### [RTU Context](trait.ModbusRTU.html)
//!
//! The RTU backend (Remote Terminal Unit) is used in serial communication and makes use of a compact, binary
//! representation of the data for protocol communication.
//! The RTU format follows the commands/data with a cyclic redundancy check checksum as an error check mechanism to
//! ensure the reliability of data.
//! Modbus RTU is the most common implementation available for Modbus. A Modbus RTU message must be transmitted
//! continuously without inter-character hesitations
//! (extract from Wikipedia, Modbus, http://en.wikipedia.org/wiki/Modbus (as of Mar. 13, 2011, 20:51 GMT).
//!
//! The Modbus RTU framing calls a slave, a device/service which handle Modbus requests, and a master, a client which
//! send requests. The communication is always initiated by the master.
//!
//! Many Modbus devices can be connected together on the same physical link so before sending a message, you must set
//! the slave (receiver) with modbus_set_slave(3).
//! If you’re running a slave, its slave number will be used to filter received messages.
//!
//! The libmodbus implementation of RTU isn’t time based as stated in original Modbus specification,
//! instead all bytes are sent as fast as possible and a response or an indication is considered complete when all
//! expected characters have been received.
//! This implementation offers very fast communication but you must take care to set a response timeout of slaves less
//! than response timeout of master
//! (ortherwise other slaves may ignore master requests when one of the slave is not responding).
//!
//! * Create a Modbus RTU context
//!     - [`new_rtu()`](struct.Modbus.html#method.new_rtu)
//!
//! * Set the serial mode
//!     - [`rtu_get_serial_mode()`](struct.Modbus.html#method.rtu_get_serial_mode),
//! [`rtu_set_serial_mode()`](struct.Modbus.html#method.rtu_set_serial_mode),
//! [`rtu_get_rts()`](struct.Modbus.html#method.rtu_get_rts), [`rtu_set_rts()`](struct.Modbus.html#method.rtu_set_rts),
//! [`rtu_set_custom_rts()`](struct.Modbus.html#method.rtu_set_custom_rts),
//! [`rtu_get_rts_delay()`](struct.Modbus.html#method.rtu_get_rts_delay),
//! [`rtu_set_rts_delay()`](struct.Modbus.html#method.rtu_set_rts_delay)
//!
//! ### [TCP (IPv4) Context](trait.ModbusTCP.html)
//! The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
//!
//! ### [TCP PI (IPv4 and IPv6) Context](trait.ModbusTCPPI.html)
//! The TCP PI (Protocol Independent) backend implements a Modbus variant used for communications over TCP IPv4 and
//! IPv6 networks.
//! It does not require a checksum calculation as lower layer takes care of the same.
//!
//! Contrary to the TCP IPv4 only backend, the TCP PI backend offers hostname resolution but it consumes about 1Kb of
//! additional memory.
//!
//! * Create a Modbus TCP context
//!     - [`new_tcp_pi()`](struct.Modbus.html#method.new_tcp_pi)
//!
//! ### Common
//!
//! Common methods to modify or change the current modbus context. Some of these function are not nessesary in Rust
//! (e.g. because the Drop trait and so on)
//!
//! * Free libmodbus context
//!     - [`free()`](struct.Modbus.html#method.free) **It should normaly not nessesary to call this function.**

//! Memory handling under Rust controlls the [`Drop trait`](https://doc.rust-lang.org/std/ops/trait.Drop.html) in
//! "the book" you'll find [more information
//! about](https://doc.rust-lang.org/book/second-edition/ch15-03-drop.html#the-drop-trait-runs-code-on-cleanup).
//! * Set slave ID
//!     - [`set_slave()`](struct.Modbus.html#method.set_slave)
//! * Enable debug mode
//!     - [`set_debug()`](struct.Modbus.html#method.set_debug)
//! * Timeout settings
//! - [`get_byte_timeout()`](struct.Modbus.html#method.get_byte_timeout)
//! [`set_byte_timeout()`](struct.Modbus.html#method.set_byte_timeout)
//! [`get_response_timeout()`](struct.Modbus.html#method.get_response_timeout)
//! [`set_response_timeout()`](struct.Modbus.html#method.set_response_timeout)
//! * Error recovery mod
//!     - [`set_error_recovery()`](struct.Modbus.html#method.set_error_recovery)
//! * Setter/getter of internal socket
//!     - [`set_socket()`](struct.Modbus.html#method.set_socket) [`get_socket()`](struct.Modbus.html#method.get_socket)
//! * Information about header
//!     - [`get_header_length()`](struct.Modbus.html#method.get_header_length)
//!
//! ### Connection
//!
//! ### [`Client`](trait.ModbusClient.html)
//!
//! The Modbus protocol defines different data types and functions to read and write them from/to remote devices.
//! The following functions are used by the clients to send Modbus requests:
//!
//! * Read data
//!     - [`read_bits()`](struct.Modbus.html#method.read_bits),
//! [`read_input_bits()`](struct.Modbus.html#method.read_input_bits),
//! [`read_registers()`](struct.Modbus.html#method.read_registers),
//! [`read_input_registers()`](struct.Modbus.html#method.read_input_registers),
//! [`report_slave_id()`](struct.Modbus.html#method.report_slave_id)
//! * Write data
//!     - [`write_bit()`](struct.Modbus.html#method.write_bit),
//! [`write_register()`](struct.Modbus.html#method.write_register),
//! [`write_bits()`](struct.Modbus.html#method.write_bits),
//! [`write_registers()`](struct.Modbus.html#method.write_registers)
//! * Write and read data
//!     - [`write_and_read_registers()`](struct.Modbus.html#method.write_and_read_registers)
//! * Raw requests
//!     - [`send_raw_request()`](struct.Modbus.html#method.send_raw_request),
//! [`receive_confirmation()`](struct.Modbus.html#method.receive_confirmation)
//! * Reply an exception
//!     - [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! ### [`Server`](trait.ModbusServer.html)
//!
//! The server is waiting for request from clients and must answer when it is concerned by the request.
//!
//! In TCP , you must not use the usual [`connect()`](struct.Modbus.html#method.connect) to establish the connection
//! but a pair of accept/listen calls
//!
//! * [`tcp_listen()`](struct.Modbus.html#method.tcp_listen), [`tcp_accept()`](struct.Modbus.html#method.tcp_accept),
//! [`tcp_pi_listen`()](struct.Modbus.html#method.tcp_pi_listen),
//! [`tcp_pi_accept`()](struct.Modbus.html#method.tcp_pi_accept)
//!
//! then the data can be received with
//!
//! * [`receive()`](struct.Modbus.html#method.receive)
//!
//! and a response can be send with
//!
//! * [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
//!
//! To handle the mapping of your Modbus data, you must use a [`ModbusMapping`](struct.ModbusMapping.html) struct:
//! [`ModbusMapping::new()`](struct.ModbusMapping.html#method.new)
//!

// `error_chain!` can recurse deeply(3)
#![recursion_limit = "1024"]

extern crate libc;
extern crate libmodbus_sys;
#[macro_use]
extern crate error_chain;

mod modbus_client;
mod modbus_mapping;
mod modbus_rtu;
mod modbus_server;
mod modbus_tcp_pi;
mod modbus_tcp;
mod modbus;
pub mod errors;

pub use self::modbus_client::ModbusClient;
pub use self::modbus_mapping::ModbusMapping;
pub use self::modbus_rtu::{ModbusRTU, RequestToSendMode, SerialMode};
pub use self::modbus_server::ModbusServer;
pub use self::modbus_tcp_pi::ModbusTCPPI;
pub use self::modbus_tcp::ModbusTCP;
pub use self::modbus::{Modbus, Timeout, ErrorRecoveryMode, Exception, FunctionCode};
pub use self::modbus::{set_bits_from_byte, set_bits_from_bytes, get_byte_from_bits, get_float_abcd, set_float_abcd,
                       get_float_badc, set_float_badc, get_float_cdab, set_float_cdab, get_float_dcba, set_float_dcba};
<|endoftext|>