<commit_before>// Copyright (C) 2020 Mathieu Duponchelle <mathieu@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use gst::glib;
use gst::gst_log;
use gst::prelude::*;
use gst::subclass::prelude::*;

use once_cell::sync::Lazy;

use std::sync::Mutex;

use crate::ttutils::{Cea608Mode, Chunk, Line, Lines, TextStyle};

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new(
        "tttojson",
        gst::DebugColorFlags::empty(),
        Some("Timed Text to JSON"),
    )
});

const DEFAULT_MODE: Cea608Mode = Cea608Mode::RollUp2;

#[derive(Debug, Clone)]
struct Settings {
    mode: Cea608Mode,
}

impl Default for Settings {
    fn default() -> Self {
        Settings { mode: DEFAULT_MODE }
    }
}

pub struct TtToJson {
    srcpad: gst::Pad,
    sinkpad: gst::Pad,
    settings: Mutex<Settings>,
}

impl TtToJson {
    fn sink_chain(
        &self,
        _pad: &gst::Pad,
        element: &super::TtToJson,
        buffer: gst::Buffer,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        let pts = buffer.pts();
        let duration = buffer.duration();

        let buffer = buffer.into_mapped_buffer_readable().map_err(|_| {
            gst::element_error!(
                element,
                gst::ResourceError::Read,
                ["Failed to map buffer readable"]
            );

            gst::FlowError::Error
        })?;

        let text = std::str::from_utf8(buffer.as_slice()).map_err(|err| {
            gst::element_error!(
                element,
                gst::ResourceError::Read,
                ["Failed to map decode as utf8: {}", err]
            );

            gst::FlowError::Error
        })?;

        let mode = self.settings.lock().unwrap().mode;

        let mut lines = Lines {
            lines: Vec::new(),
            mode: Some(mode),
            clear: Some(false),
        };

        for phrase in text.lines() {
            lines.lines.push(Line {
                carriage_return: Some(true),
                column: Some(0),
                row: Some(13),
                chunks: vec![Chunk {
                    // Default CEA 608 styling
                    style: TextStyle::White,
                    underline: false,
                    text: phrase.to_string(),
                }],
            });
        }

        let json = serde_json::to_string(&lines).map_err(|err| {
            gst::element_error!(
                element,
                gst::ResourceError::Write,
                ["Failed to serialize as json {}", err]
            );

            gst::FlowError::Error
        })?;

        let mut buf = gst::Buffer::from_mut_slice(json.into_bytes());
        {
            let buf_mut = buf.get_mut().unwrap();
            buf_mut.set_pts(pts);
            buf_mut.set_duration(duration);
        }

        self.srcpad.push(buf)
    }

    fn sink_event(&self, pad: &gst::Pad, element: &super::TtToJson, event: gst::Event) -> bool {
        use gst::EventView;

        gst_log!(CAT, obj: pad, "Handling event {:?}", event);

        match event.view() {
            EventView::Caps(_) => {
                // We send our own caps downstream
                let caps = gst::Caps::builder("application/x-json")
                    .field("format", "cea608")
                    .build();
                self.srcpad.push_event(gst::event::Caps::new(&caps))
            }
            EventView::Eos(_) => pad.event_default(Some(element), event),
            _ => pad.event_default(Some(element), event),
        }
    }
}

impl GstObjectImpl for TtToJson {}

impl ElementImpl for TtToJson {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "Timed text to JSON encoder",
                "Encoder/ClosedCaption",
                "Encodes Timed Text to JSON",
                "Mathieu Duponchelle <mathieu@centricular.com>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let caps = gst::Caps::builder("text/x-raw")
                .field("format", "utf8")
                .build();
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &caps,
            )
            .unwrap();

            let caps = gst::Caps::builder("application/x-json").build();
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &caps,
            )
            .unwrap();

            vec![src_pad_template, sink_pad_template]
        });

        PAD_TEMPLATES.as_ref()
    }
}

#[glib::object_subclass]
impl ObjectSubclass for TtToJson {
    const NAME: &'static str = "RsTtToJson";
    type Type = super::TtToJson;
    type ParentType = gst::Element;

    fn with_class(klass: &Self::Class) -> Self {
        let templ = klass.pad_template("sink").unwrap();
        let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink"))
            .chain_function(|pad, parent, buffer| {
                TtToJson::catch_panic_pad_function(
                    parent,
                    || Err(gst::FlowError::Error),
                    |enc, element| enc.sink_chain(pad, element, buffer),
                )
            })
            .event_function(|pad, parent, event| {
                TtToJson::catch_panic_pad_function(
                    parent,
                    || false,
                    |enc, element| enc.sink_event(pad, element, event),
                )
            })
            .build();

        let templ = klass.pad_template("src").unwrap();
        let srcpad = gst::Pad::builder_with_template(&templ, Some("src")).build();

        Self {
            srcpad,
            sinkpad,
            settings: Mutex::new(Settings::default()),
        }
    }
}

impl ObjectImpl for TtToJson {
    fn properties() -> &'static [glib::ParamSpec] {
        static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
            vec![glib::ParamSpec::new_enum(
                "mode",
                "Mode",
                "Which mode to operate in",
                Cea608Mode::static_type(),
                DEFAULT_MODE as i32,
                glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
            )]
        });

        PROPERTIES.as_ref()
    }

    fn constructed(&self, obj: &Self::Type) {
        self.parent_constructed(obj);

        obj.add_pad(&self.sinkpad).unwrap();
        obj.add_pad(&self.srcpad).unwrap();
    }

    fn set_property(
        &self,
        _obj: &Self::Type,
        _id: usize,
        value: &glib::Value,
        pspec: &glib::ParamSpec,
    ) {
        match pspec.name() {
            "mode" => {
                let mut settings = self.settings.lock().unwrap();
                settings.mode = value.get::<Cea608Mode>().expect("type checked upstream");
            }
            _ => unimplemented!(),
        }
    }

    fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
        match pspec.name() {
            "mode" => {
                let settings = self.settings.lock().unwrap();
                settings.mode.to_value()
            }
            _ => unimplemented!(),
        }
    }
}
<commit_msg>tttojson: fix row computation<commit_after>// Copyright (C) 2020 Mathieu Duponchelle <mathieu@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use gst::glib;
use gst::gst_log;
use gst::prelude::*;
use gst::subclass::prelude::*;

use once_cell::sync::Lazy;

use std::cmp::min;
use std::sync::Mutex;

use crate::ttutils::{Cea608Mode, Chunk, Line, Lines, TextStyle};

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new(
        "tttojson",
        gst::DebugColorFlags::empty(),
        Some("Timed Text to JSON"),
    )
});

const DEFAULT_MODE: Cea608Mode = Cea608Mode::RollUp2;

#[derive(Debug, Clone)]
struct Settings {
    mode: Cea608Mode,
}

impl Default for Settings {
    fn default() -> Self {
        Settings { mode: DEFAULT_MODE }
    }
}

pub struct TtToJson {
    srcpad: gst::Pad,
    sinkpad: gst::Pad,
    settings: Mutex<Settings>,
}

impl TtToJson {
    fn sink_chain(
        &self,
        _pad: &gst::Pad,
        element: &super::TtToJson,
        buffer: gst::Buffer,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        let pts = buffer.pts();
        let duration = buffer.duration();

        let buffer = buffer.into_mapped_buffer_readable().map_err(|_| {
            gst::element_error!(
                element,
                gst::ResourceError::Read,
                ["Failed to map buffer readable"]
            );

            gst::FlowError::Error
        })?;

        let text = std::str::from_utf8(buffer.as_slice()).map_err(|err| {
            gst::element_error!(
                element,
                gst::ResourceError::Read,
                ["Failed to map decode as utf8: {}", err]
            );

            gst::FlowError::Error
        })?;

        let mode = self.settings.lock().unwrap().mode;

        let mut lines = Lines {
            lines: Vec::new(),
            mode: Some(mode),
            clear: Some(false),
        };

        let mut row = min(15usize.saturating_sub(text.lines().count()), 13usize) as u32;

        for phrase in text.lines() {
            lines.lines.push(Line {
                carriage_return: Some(true),
                column: Some(0),
                row: Some(row),
                chunks: vec![Chunk {
                    // Default CEA 608 styling
                    style: TextStyle::White,
                    underline: false,
                    text: phrase.to_string(),
                }],
            });

            row = min(14u32, row + 1);
        }

        let json = serde_json::to_string(&lines).map_err(|err| {
            gst::element_error!(
                element,
                gst::ResourceError::Write,
                ["Failed to serialize as json {}", err]
            );

            gst::FlowError::Error
        })?;

        let mut buf = gst::Buffer::from_mut_slice(json.into_bytes());
        {
            let buf_mut = buf.get_mut().unwrap();
            buf_mut.set_pts(pts);
            buf_mut.set_duration(duration);
        }

        self.srcpad.push(buf)
    }

    fn sink_event(&self, pad: &gst::Pad, element: &super::TtToJson, event: gst::Event) -> bool {
        use gst::EventView;

        gst_log!(CAT, obj: pad, "Handling event {:?}", event);

        match event.view() {
            EventView::Caps(_) => {
                // We send our own caps downstream
                let caps = gst::Caps::builder("application/x-json")
                    .field("format", "cea608")
                    .build();
                self.srcpad.push_event(gst::event::Caps::new(&caps))
            }
            EventView::Eos(_) => pad.event_default(Some(element), event),
            _ => pad.event_default(Some(element), event),
        }
    }
}

impl GstObjectImpl for TtToJson {}

impl ElementImpl for TtToJson {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "Timed text to JSON encoder",
                "Encoder/ClosedCaption",
                "Encodes Timed Text to JSON",
                "Mathieu Duponchelle <mathieu@centricular.com>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let caps = gst::Caps::builder("text/x-raw")
                .field("format", "utf8")
                .build();
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &caps,
            )
            .unwrap();

            let caps = gst::Caps::builder("application/x-json").build();
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &caps,
            )
            .unwrap();

            vec![src_pad_template, sink_pad_template]
        });

        PAD_TEMPLATES.as_ref()
    }
}

#[glib::object_subclass]
impl ObjectSubclass for TtToJson {
    const NAME: &'static str = "RsTtToJson";
    type Type = super::TtToJson;
    type ParentType = gst::Element;

    fn with_class(klass: &Self::Class) -> Self {
        let templ = klass.pad_template("sink").unwrap();
        let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink"))
            .chain_function(|pad, parent, buffer| {
                TtToJson::catch_panic_pad_function(
                    parent,
                    || Err(gst::FlowError::Error),
                    |enc, element| enc.sink_chain(pad, element, buffer),
                )
            })
            .event_function(|pad, parent, event| {
                TtToJson::catch_panic_pad_function(
                    parent,
                    || false,
                    |enc, element| enc.sink_event(pad, element, event),
                )
            })
            .build();

        let templ = klass.pad_template("src").unwrap();
        let srcpad = gst::Pad::builder_with_template(&templ, Some("src")).build();

        Self {
            srcpad,
            sinkpad,
            settings: Mutex::new(Settings::default()),
        }
    }
}

impl ObjectImpl for TtToJson {
    fn properties() -> &'static [glib::ParamSpec] {
        static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
            vec![glib::ParamSpec::new_enum(
                "mode",
                "Mode",
                "Which mode to operate in",
                Cea608Mode::static_type(),
                DEFAULT_MODE as i32,
                glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
            )]
        });

        PROPERTIES.as_ref()
    }

    fn constructed(&self, obj: &Self::Type) {
        self.parent_constructed(obj);

        obj.add_pad(&self.sinkpad).unwrap();
        obj.add_pad(&self.srcpad).unwrap();
    }

    fn set_property(
        &self,
        _obj: &Self::Type,
        _id: usize,
        value: &glib::Value,
        pspec: &glib::ParamSpec,
    ) {
        match pspec.name() {
            "mode" => {
                let mut settings = self.settings.lock().unwrap();
                settings.mode = value.get::<Cea608Mode>().expect("type checked upstream");
            }
            _ => unimplemented!(),
        }
    }

    fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
        match pspec.name() {
            "mode" => {
                let settings = self.settings.lock().unwrap();
                settings.mode.to_value()
            }
            _ => unimplemented!(),
        }
    }
}
<|endoftext|>


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

use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Range;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use memory::Content;
use OomError;
use SafeDeref;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
///
/// The destructor of `DeviceMemory` automatically frees the memory.
///
/// # Example
///
/// ```no_run
/// use vulkano::memory::DeviceMemory;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = unsafe { ::std::mem::uninitialized() };
/// let mem_ty = device.physical_device().memory_types().next().unwrap();
///
/// // Allocates 1kB of memory.
/// let memory = DeviceMemory::alloc(&device, mem_ty, 1024).unwrap();
/// ```
#[derive(Debug)]
pub struct DeviceMemory<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    memory: vk::DeviceMemory,
    device: D,
    size: usize,
    memory_type_index: u32,
}

impl<D> DeviceMemory<D> where D: SafeDeref<Target = Device> {
    /// Allocates a chunk of memory from the device.
    ///
    /// Some platforms may have a limit on the maximum size of a single allocation. For example,
    /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
    ///
    /// # Panic
    ///
    /// - Panics if `size` is 0.
    /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    // TODO: VK_ERROR_TOO_MANY_OBJECTS error
    // TODO: remove that `D` generic and use `Arc<Device>`
    #[inline]
    pub fn alloc(device: &D, memory_type: MemoryType, size: usize)
                 -> Result<DeviceMemory<D>, OomError>
        where D: Clone
    {
        assert!(size >= 1);
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        if size > memory_type.heap().size() {
            return Err(OomError::OutOfDeviceMemory);
        }

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            memory: memory,
            device: device.clone(),
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panics if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &D, memory_type: MemoryType, size: usize)
                         -> Result<MappedDeviceMemory<D>, OomError>
        where D: Clone
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let coherent = memory_type.is_host_coherent();

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
            coherent: coherent,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Device {
        &self.device
    }
}

unsafe impl<D> VulkanObject for DeviceMemory<D> where D: SafeDeref<Target = Device> {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl<D> Drop for DeviceMemory<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let device = self.device();
            let vk = device.pointers();
            vk.FreeMemory(device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
///
/// Can be obtained with `DeviceMemory::alloc_and_map`. The function will panic if the memory type
/// is not host-accessible.
///
/// In order to access the content of the allocated memory, you can use the `read_write` method.
/// This method returns a guard object that derefs to the content.
///
/// # Example
///
/// ```no_run
/// use vulkano::memory::DeviceMemory;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = unsafe { ::std::mem::uninitialized() };
/// // The memory type must be mappable.
/// let mem_ty = device.physical_device().memory_types()
///                     .filter(|t| t.is_host_visible())
///                     .next().unwrap();    // Vk specs guarantee that this can't fail
///
/// // Allocates 1kB of memory.
/// let memory = DeviceMemory::alloc_and_map(&device, mem_ty, 1024).unwrap();
///
/// // Get access to the content. Note that this is very unsafe for two reasons: 1) the content is
/// // uninitialized, and 2) the access is unsynchronized.
/// unsafe {
///     let mut content = memory.read_write::<[u8]>(0 .. 1024);
///     content[12] = 54;       // `content` derefs to a `&[u8]` or a `&mut [u8]`
/// }
/// ```
#[derive(Debug)]
pub struct MappedDeviceMemory<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    memory: DeviceMemory<D>,
    pointer: *mut c_void,
    coherent: bool,
}

impl<D> MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {
    /// Returns the underlying `DeviceMemory`.
    // TODO: impl AsRef instead?
    #[inline]
    pub fn memory(&self) -> &DeviceMemory<D> {
        &self.memory
    }

    /// Gives access to the content of the memory.
    ///
    /// This function takes care of calling `vkInvalidateMappedMemoryRanges` and
    /// `vkFlushMappedMemoryRanges` on the given range. You are therefore encouraged to use the
    /// smallest range as possible, and to not call this function multiple times in a row for
    /// several small changes.
    ///
    /// # Safety
    ///
    /// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
    ///   buffer.
    /// - Accesses are not synchronized. Synchronization must be handled outside of
    ///   the `MappedDeviceMemory`.
    ///
    #[inline]
    pub unsafe fn read_write<T: ?Sized>(&self, range: Range<usize>) -> CpuAccess<T, D>
        where T: Content + 'static
    {
        let vk = self.memory.device().pointers();
        let pointer = T::ref_from_ptr((self.pointer as usize + range.start) as *mut _,
                                      range.end - range.start).unwrap();       // TODO: error

        if !self.coherent {
            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.memory.internal_object(),
                offset: range.start as u64,
                size: (range.end - range.start) as u64,
            };

            // TODO: check result?
            vk.InvalidateMappedMemoryRanges(self.memory.device().internal_object(), 1, &range);
        }

        CpuAccess {
            pointer: pointer,
            mem: self,
            coherent: self.coherent,
            range: range,
        }
    }
}

unsafe impl<D> Send for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {}
unsafe impl<D> Sync for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {}

impl<D> Drop for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let device = self.memory.device();
            let vk = device.pointers();
            vk.UnmapMemory(device.internal_object(), self.memory.memory);
        }
    }
}

/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
///
/// This object derefs to the content, just like a `MutexGuard` for example.
pub struct CpuAccess<'a, T: ?Sized + 'a, D = Arc<Device>> where D: SafeDeref<Target = Device> + 'a {
    pointer: *mut T,
    mem: &'a MappedDeviceMemory<D>,
    coherent: bool,
    range: Range<usize>,
}

impl<'a, T: ?Sized + 'a, D: 'a> CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    /// Builds a new `CpuAccess` to access a sub-part of the current `CpuAccess`.
    ///
    /// This function is unstable. Don't use it directly.
    // TODO: unsafe?
    // TODO: decide what to do with this
    #[doc(hidden)]
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> CpuAccess<'a, U, D>
        where F: FnOnce(*mut T) -> *mut U
    {
        CpuAccess {
            pointer: f(self.pointer),
            mem: self.mem,
            coherent: self.coherent,
            range: self.range.clone(),  // TODO: ?
        }
    }
}

unsafe impl<'a, T: ?Sized + 'a, D: 'a> Send for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device> {}
unsafe impl<'a, T: ?Sized + 'a, D: 'a> Sync for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device> {}

impl<'a, T: ?Sized + 'a, D: 'a> Deref for CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a, D: 'a> DerefMut for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device>
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a, D: 'a> Drop for CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        // If the memory doesn't have the `coherent` flag, we need to flush the data.
        if !self.coherent {
            let vk = self.mem.memory().device().pointers();

            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.mem.memory().internal_object(),
                offset: self.range.start as u64,
                size: (self.range.end - self.range.start) as u64,
            };

            // TODO: check result?
            unsafe {
                vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                           1, &range);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use OomError;
    use memory::DeviceMemory;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, mem_ty, 256).unwrap();
    }

    #[test]
    #[should_panic]
    fn zero_size() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, mem_ty, 0);
    }

    #[test]
    #[cfg(target_pointer_width = "64")]
    fn oom_single() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();

        match DeviceMemory::alloc(&device, mem_ty, 0xffffffffffffffff) {
            Err(OomError::OutOfDeviceMemory) => (),
            _ => panic!()
        }
    }

    #[test]
    fn oom_multi() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();
        let heap_size = mem_ty.heap().size();

        let mut allocs = Vec::new();

        for _ in 0 .. 4 {
            match DeviceMemory::alloc(&device, mem_ty, heap_size / 3) {
                Err(OomError::OutOfDeviceMemory) => return,     // test succeeded
                Ok(a) => allocs.push(a),
                _ => ()
            }
        }

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

use std::mem;
use std::ptr;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Range;
use std::os::raw::c_void;
use std::sync::Arc;

use instance::MemoryType;
use device::Device;
use memory::Content;
use OomError;
use SafeDeref;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents memory that has been allocated.
///
/// The destructor of `DeviceMemory` automatically frees the memory.
///
/// # Example
///
/// ```
/// use vulkano::memory::DeviceMemory;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// let mem_ty = device.physical_device().memory_types().next().unwrap();
///
/// // Allocates 1kB of memory.
/// let memory = DeviceMemory::alloc(&device, mem_ty, 1024).unwrap();
/// ```
#[derive(Debug)]
pub struct DeviceMemory<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    memory: vk::DeviceMemory,
    device: D,
    size: usize,
    memory_type_index: u32,
}

impl<D> DeviceMemory<D> where D: SafeDeref<Target = Device> {
    /// Allocates a chunk of memory from the device.
    ///
    /// Some platforms may have a limit on the maximum size of a single allocation. For example,
    /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
    ///
    /// # Panic
    ///
    /// - Panics if `size` is 0.
    /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
    ///
    // TODO: VK_ERROR_TOO_MANY_OBJECTS error
    // TODO: remove that `D` generic and use `Arc<Device>`
    #[inline]
    pub fn alloc(device: &D, memory_type: MemoryType, size: usize)
                 -> Result<DeviceMemory<D>, OomError>
        where D: Clone
    {
        assert!(size >= 1);
        assert_eq!(device.physical_device().internal_object(),
                   memory_type.physical_device().internal_object());

        if size > memory_type.heap().size() {
            return Err(OomError::OutOfDeviceMemory);
        }

        let vk = device.pointers();

        let memory = unsafe {
            let infos = vk::MemoryAllocateInfo {
                sType: vk::STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: size as u64,
                memoryTypeIndex: memory_type.id(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateMemory(device.internal_object(), &infos,
                                                ptr::null(), &mut output)));
            output
        };

        Ok(DeviceMemory {
            memory: memory,
            device: device.clone(),
            size: size,
            memory_type_index: memory_type.id(),
        })
    }

    /// Allocates a chunk of memory and maps it.
    ///
    /// # Panic
    ///
    /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
    /// - Panics if the memory type is not host-visible.
    ///
    pub fn alloc_and_map(device: &D, memory_type: MemoryType, size: usize)
                         -> Result<MappedDeviceMemory<D>, OomError>
        where D: Clone
    {
        let vk = device.pointers();

        assert!(memory_type.is_host_visible());
        let mem = try!(DeviceMemory::alloc(device, memory_type, size));

        let coherent = memory_type.is_host_coherent();

        let ptr = unsafe {
            let mut output = mem::uninitialized();
            try!(check_errors(vk.MapMemory(device.internal_object(), mem.memory, 0,
                                           mem.size as vk::DeviceSize, 0 /* reserved flags */,
                                           &mut output)));
            output
        };

        Ok(MappedDeviceMemory {
            memory: mem,
            pointer: ptr,
            coherent: coherent,
        })
    }

    /// Returns the memory type this chunk was allocated on.
    #[inline]
    pub fn memory_type(&self) -> MemoryType {
        self.device.physical_device().memory_type_by_id(self.memory_type_index).unwrap()
    }

    /// Returns the size in bytes of that memory chunk.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }

    /// Returns the device associated with this allocation.
    #[inline]
    pub fn device(&self) -> &Device {
        &self.device
    }
}

unsafe impl<D> VulkanObject for DeviceMemory<D> where D: SafeDeref<Target = Device> {
    type Object = vk::DeviceMemory;

    #[inline]
    fn internal_object(&self) -> vk::DeviceMemory {
        self.memory
    }
}

impl<D> Drop for DeviceMemory<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let device = self.device();
            let vk = device.pointers();
            vk.FreeMemory(device.internal_object(), self.memory, ptr::null());
        }
    }
}

/// Represents memory that has been allocated and mapped in CPU accessible space.
///
/// Can be obtained with `DeviceMemory::alloc_and_map`. The function will panic if the memory type
/// is not host-accessible.
///
/// In order to access the content of the allocated memory, you can use the `read_write` method.
/// This method returns a guard object that derefs to the content.
///
/// # Example
///
/// ```
/// use vulkano::memory::DeviceMemory;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// // The memory type must be mappable.
/// let mem_ty = device.physical_device().memory_types()
///                     .filter(|t| t.is_host_visible())
///                     .next().unwrap();    // Vk specs guarantee that this can't fail
///
/// // Allocates 1kB of memory.
/// let memory = DeviceMemory::alloc_and_map(&device, mem_ty, 1024).unwrap();
///
/// // Get access to the content. Note that this is very unsafe for two reasons: 1) the content is
/// // uninitialized, and 2) the access is unsynchronized.
/// unsafe {
///     let mut content = memory.read_write::<[u8]>(0 .. 1024);
///     content[12] = 54;       // `content` derefs to a `&[u8]` or a `&mut [u8]`
/// }
/// ```
#[derive(Debug)]
pub struct MappedDeviceMemory<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    memory: DeviceMemory<D>,
    pointer: *mut c_void,
    coherent: bool,
}

impl<D> MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {
    /// Returns the underlying `DeviceMemory`.
    // TODO: impl AsRef instead?
    #[inline]
    pub fn memory(&self) -> &DeviceMemory<D> {
        &self.memory
    }

    /// Gives access to the content of the memory.
    ///
    /// This function takes care of calling `vkInvalidateMappedMemoryRanges` and
    /// `vkFlushMappedMemoryRanges` on the given range. You are therefore encouraged to use the
    /// smallest range as possible, and to not call this function multiple times in a row for
    /// several small changes.
    ///
    /// # Safety
    ///
    /// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
    ///   buffer.
    /// - Accesses are not synchronized. Synchronization must be handled outside of
    ///   the `MappedDeviceMemory`.
    ///
    #[inline]
    pub unsafe fn read_write<T: ?Sized>(&self, range: Range<usize>) -> CpuAccess<T, D>
        where T: Content + 'static
    {
        let vk = self.memory.device().pointers();
        let pointer = T::ref_from_ptr((self.pointer as usize + range.start) as *mut _,
                                      range.end - range.start).unwrap();       // TODO: error

        if !self.coherent {
            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.memory.internal_object(),
                offset: range.start as u64,
                size: (range.end - range.start) as u64,
            };

            // TODO: check result?
            vk.InvalidateMappedMemoryRanges(self.memory.device().internal_object(), 1, &range);
        }

        CpuAccess {
            pointer: pointer,
            mem: self,
            coherent: self.coherent,
            range: range,
        }
    }
}

unsafe impl<D> Send for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {}
unsafe impl<D> Sync for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {}

impl<D> Drop for MappedDeviceMemory<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let device = self.memory.device();
            let vk = device.pointers();
            vk.UnmapMemory(device.internal_object(), self.memory.memory);
        }
    }
}

/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
///
/// This object derefs to the content, just like a `MutexGuard` for example.
pub struct CpuAccess<'a, T: ?Sized + 'a, D = Arc<Device>> where D: SafeDeref<Target = Device> + 'a {
    pointer: *mut T,
    mem: &'a MappedDeviceMemory<D>,
    coherent: bool,
    range: Range<usize>,
}

impl<'a, T: ?Sized + 'a, D: 'a> CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    /// Builds a new `CpuAccess` to access a sub-part of the current `CpuAccess`.
    ///
    /// This function is unstable. Don't use it directly.
    // TODO: unsafe?
    // TODO: decide what to do with this
    #[doc(hidden)]
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> CpuAccess<'a, U, D>
        where F: FnOnce(*mut T) -> *mut U
    {
        CpuAccess {
            pointer: f(self.pointer),
            mem: self.mem,
            coherent: self.coherent,
            range: self.range.clone(),  // TODO: ?
        }
    }
}

unsafe impl<'a, T: ?Sized + 'a, D: 'a> Send for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device> {}
unsafe impl<'a, T: ?Sized + 'a, D: 'a> Sync for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device> {}

impl<'a, T: ?Sized + 'a, D: 'a> Deref for CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.pointer }
    }
}

impl<'a, T: ?Sized + 'a, D: 'a> DerefMut for CpuAccess<'a, T, D>
    where D: SafeDeref<Target = Device>
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.pointer }
    }
}

impl<'a, T: ?Sized + 'a, D: 'a> Drop for CpuAccess<'a, T, D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        // If the memory doesn't have the `coherent` flag, we need to flush the data.
        if !self.coherent {
            let vk = self.mem.memory().device().pointers();

            let range = vk::MappedMemoryRange {
                sType: vk::STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
                pNext: ptr::null(),
                memory: self.mem.memory().internal_object(),
                offset: self.range.start as u64,
                size: (self.range.end - self.range.start) as u64,
            };

            // TODO: check result?
            unsafe {
                vk.FlushMappedMemoryRanges(self.mem.memory().device().internal_object(),
                                           1, &range);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use OomError;
    use memory::DeviceMemory;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, mem_ty, 256).unwrap();
    }

    #[test]
    #[should_panic]
    fn zero_size() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().next().unwrap();
        let _ = DeviceMemory::alloc(&device, mem_ty, 0);
    }

    #[test]
    #[cfg(target_pointer_width = "64")]
    fn oom_single() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();

        match DeviceMemory::alloc(&device, mem_ty, 0xffffffffffffffff) {
            Err(OomError::OutOfDeviceMemory) => (),
            _ => panic!()
        }
    }

    #[test]
    fn oom_multi() {
        let (device, _) = gfx_dev_and_queue!();
        let mem_ty = device.physical_device().memory_types().filter(|m| !m.is_lazily_allocated())
                           .next().unwrap();
        let heap_size = mem_ty.heap().size();

        let mut allocs = Vec::new();

        for _ in 0 .. 4 {
            match DeviceMemory::alloc(&device, mem_ty, heap_size / 3) {
                Err(OomError::OutOfDeviceMemory) => return,     // test succeeded
                Ok(a) => allocs.push(a),
                _ => ()
            }
        }

        panic!()
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#![allow(unused)]
#![deny(clippy, clippy_pedantic)]

use std::collections::BTreeMap;
use std::collections::HashMap;
use std::ops::Mul;

struct T;

impl T {
    fn add(self, other: T) -> T { self } //~ERROR defining a method called `add`
    fn drop(&mut self) { } //~ERROR defining a method called `drop`

    fn sub(&self, other: T) -> &T { self } // no error, self is a ref
    fn div(self) -> T { self } // no error, different #arguments
    fn rem(self, other: T) { } // no error, wrong return type

    fn into_u32(self) -> u32 { 0 } // fine
    fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value

    fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference
}

#[derive(Clone,Copy)]
struct U;

impl U {
    fn to_something(self) -> u32 { 0 } // ok because U is Copy
}

impl Mul<T> for T {
    type Output = T;
    fn mul(self, other: T) -> T { self } // no error, obviously
}

/// Utility macro to test linting behavior in `option_methods()`
/// The lints included in `option_methods()` should not lint if the call to map is partially
/// within a macro
macro_rules! opt_map {
    ($opt:expr, $map:expr) => {($opt).map($map)};
}

/// Checks implementation of the following lints:
/// OPTION_MAP_UNWRAP_OR
/// OPTION_MAP_UNWRAP_OR_ELSE
fn option_methods() {
    let opt = Some(1);

    // Check OPTION_MAP_UNWRAP_OR
    // single line case
    let _ = opt.map(|x| x + 1) //~  ERROR called `map(f).unwrap_or(a)`
                               //~| NOTE replace `map(|x| x + 1).unwrap_or(0)`
               .unwrap_or(0); // should lint even though this call is on a separate line
    // multi line cases
    let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)`
                        x + 1
                    }
              ).unwrap_or(0);
    let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)`
               .unwrap_or({
                    0
                });
    // macro case
    let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint

    // Check OPTION_MAP_UNWRAP_OR_ELSE
    // single line case
    let _ = opt.map(|x| x + 1) //~  ERROR called `map(f).unwrap_or_else(g)`
                               //~| NOTE replace `map(|x| x + 1).unwrap_or_else(|| 0)`
               .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
    // multi line cases
    let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or_else(g)`
                        x + 1
                    }
              ).unwrap_or_else(|| 0);
    let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)`
               .unwrap_or_else(||
                    0
                );
    // macro case
    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint

}

/// Struct to generate false positive for Iterator-based lints
#[derive(Copy, Clone)]
struct IteratorFalsePositives {
    foo: u32,
}

impl IteratorFalsePositives {
    fn filter(self) -> IteratorFalsePositives {
        self
    }

    fn next(self) -> IteratorFalsePositives {
        self
    }

    fn find(self) -> Option<u32> {
        Some(self.foo)
    }

    fn position(self) -> Option<u32> {
        Some(self.foo)
    }

    fn rposition(self) -> Option<u32> {
        Some(self.foo)
    }
}

/// Checks implementation of FILTER_NEXT lint
fn filter_next() {
    let v = vec![3, 2, 1, 0, -1, -2, -3];

    // check single-line case
    let _ = v.iter().filter(|&x| *x < 0).next();
    //~^ ERROR called `filter(p).next()` on an Iterator.
    //~| NOTE replace `filter(|&x| *x < 0).next()`

    // check multi-line case
    let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator.
                                *x < 0
                            }
                   ).next();

    // check that we don't lint if the caller is not an Iterator
    let foo = IteratorFalsePositives { foo: 0 };
    let _ = foo.filter().next();
}

/// Checks implementation of SEARCH_IS_SOME lint
fn search_is_some() {
    let v = vec![3, 2, 1, 0, -1, -2, -3];

    // check `find().is_some()`, single-line
    let _ = v.iter().find(|&x| *x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `find(|&x| *x < 0).is_some()`

    // check `find().is_some()`, multi-line
    let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching
                              *x < 0
                          }
                   ).is_some();

    // check `position().is_some()`, single-line
    let _ = v.iter().position(|&x| x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `position(|&x| x < 0).is_some()`

    // check `position().is_some()`, multi-line
    let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching
                                  x < 0
                              }
                   ).is_some();

    // check `rposition().is_some()`, single-line
    let _ = v.iter().rposition(|&x| x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `rposition(|&x| x < 0).is_some()`

    // check `rposition().is_some()`, multi-line
    let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching
                                   x < 0
                               }
                   ).is_some();

    // check that we don't lint if the caller is not an Iterator
    let foo = IteratorFalsePositives { foo: 0 };
    let _ = foo.find().is_some();
    let _ = foo.position().is_some();
    let _ = foo.rposition().is_some();
}

/// Checks implementation of the OR_FUN_CALL lint
fn or_fun_call() {
    struct Foo;

    impl Foo {
        fn new() -> Foo { Foo }
    }

    fn make<T>() -> T { unimplemented!(); }

    let with_constructor = Some(vec![1]);
    with_constructor.unwrap_or(make());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_constructor.unwrap_or_else(make)

    let with_new = Some(vec![1]);
    with_new.unwrap_or(Vec::new());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_new.unwrap_or_default();

    let with_const_args = Some(vec![1]);
    with_const_args.unwrap_or(Vec::with_capacity(12));
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_const_args.unwrap_or_else(|| Vec::with_capacity(12));

    let with_err : Result<_, ()> = Ok(vec![1]);
    with_err.unwrap_or(make());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_err.unwrap_or_else(|_| make());

    let with_err_args : Result<_, ()> = Ok(vec![1]);
    with_err_args.unwrap_or(Vec::with_capacity(12));
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_err_args.unwrap_or_else(|_| Vec::with_capacity(12));

    let with_default_trait = Some(1);
    with_default_trait.unwrap_or(Default::default());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_default_trait.unwrap_or_default();

    let with_default_type = Some(1);
    with_default_type.unwrap_or(u64::default());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_default_type.unwrap_or_default();

    let with_vec = Some(vec![1]);
    with_vec.unwrap_or(vec![]);
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);

    let without_default = Some(Foo);
    without_default.unwrap_or(Foo::new());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION without_default.unwrap_or_else(Foo::new);

    let mut map = HashMap::<u64, String>::new();
    map.entry(42).or_insert(String::new());
    //~^ERROR use of `or_insert` followed by a function call
    //~|HELP try this
    //~|SUGGESTION map.entry(42).or_insert_with(String::new);

    let mut btree = BTreeMap::<u64, String>::new();
    btree.entry(42).or_insert(String::new());
    //~^ERROR use of `or_insert` followed by a function call
    //~|HELP try this
    //~|SUGGESTION btree.entry(42).or_insert_with(String::new);
}

fn main() {
    use std::io;

    let opt = Some(0);
    let _ = opt.unwrap();  //~ERROR used unwrap() on an Option

    let res: Result<i32, ()> = Ok(0);
    let _ = res.unwrap();  //~ERROR used unwrap() on a Result

    let _ = "str".to_string();  //~ERROR `"str".to_owned()` is faster

    let v = &"str";
    let string = v.to_string();  //~ERROR `(*v).to_owned()` is faster
    let _again = string.to_string();  //~ERROR `String::to_string` is an inefficient way to clone a `String`; use `clone()` instead

    res.ok().expect("disaster!"); //~ERROR called `ok().expect()`
    // the following should not warn, since `expect` isn't implemented unless
    // the error type implements `Debug`
    let res2: Result<i32, MyError> = Ok(0);
    res2.ok().expect("oh noes!");
    // we currently don't warn if the error type has a type parameter
    // (but it would be nice if we did)
    let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0);
    res3.ok().expect("whoof");
    let res4: Result<u32, io::Error> = Ok(0);
    res4.ok().expect("argh"); //~ERROR called `ok().expect()`
    let res5: io::Result<u32> = Ok(0);
    res5.ok().expect("oops"); //~ERROR called `ok().expect()`
    let res6: Result<u32, &str> = Ok(0);
    res6.ok().expect("meh"); //~ERROR called `ok().expect()`
}

struct MyError(()); // doesn't implement Debug

#[derive(Debug)]
struct MyErrorWithParam<T> {
    x: T
}

fn starts_with() {
    "".chars().next() == Some(' ');
    //~^ ERROR starts_with
    //~| HELP like this
    //~| SUGGESTION "".starts_with(' ')

    Some(' ') != "".chars().next();
    //~^ ERROR starts_with
    //~| HELP like this
    //~| SUGGESTION !"".starts_with(' ')
}

fn use_extend_from_slice() {
    let mut v : Vec<&'static str> = vec![];
    v.extend(&["Hello", "World"]); //~ERROR use of `extend`
    v.extend(&vec!["Some", "more"]);
    //~^ERROR use of `extend`
    //~| HELP try this
    //~| SUGGESTION v.extend_from_slice(&vec!["Some", "more"]);

    v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend`
    let o : Option<&'static str> = None;
    v.extend(o);
    v.extend(Some("Bye"));
    v.extend(vec!["Not", "like", "this"]);
    v.extend(["But", "this"].iter());
    //~^ERROR use of `extend
    //~| HELP try this
    //~| SUGGESTION v.extend_from_slice(&["But", "this"]);
}

fn clone_on_copy() {
    42.clone(); //~ERROR using `clone` on a `Copy` type
    vec![1].clone(); // ok, not a Copy type
    Some(vec![1]).clone(); // ok, not a Copy type
}

fn clone_on_copy_generic<T: Copy>(t: T) {
    t.clone(); //~ERROR using `clone` on a `Copy` type
    Some(t).clone(); //~ERROR using `clone` on a `Copy` type
}
<commit_msg>Test for double-ref lint<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#![deny(clippy, clippy_pedantic)]
#![allow(unused, print_stdout)]

use std::collections::BTreeMap;
use std::collections::HashMap;
use std::ops::Mul;

struct T;

impl T {
    fn add(self, other: T) -> T { self } //~ERROR defining a method called `add`
    fn drop(&mut self) { } //~ERROR defining a method called `drop`

    fn sub(&self, other: T) -> &T { self } // no error, self is a ref
    fn div(self) -> T { self } // no error, different #arguments
    fn rem(self, other: T) { } // no error, wrong return type

    fn into_u32(self) -> u32 { 0 } // fine
    fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value

    fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference
}

#[derive(Clone,Copy)]
struct U;

impl U {
    fn to_something(self) -> u32 { 0 } // ok because U is Copy
}

impl Mul<T> for T {
    type Output = T;
    fn mul(self, other: T) -> T { self } // no error, obviously
}

/// Utility macro to test linting behavior in `option_methods()`
/// The lints included in `option_methods()` should not lint if the call to map is partially
/// within a macro
macro_rules! opt_map {
    ($opt:expr, $map:expr) => {($opt).map($map)};
}

/// Checks implementation of the following lints:
/// OPTION_MAP_UNWRAP_OR
/// OPTION_MAP_UNWRAP_OR_ELSE
fn option_methods() {
    let opt = Some(1);

    // Check OPTION_MAP_UNWRAP_OR
    // single line case
    let _ = opt.map(|x| x + 1) //~  ERROR called `map(f).unwrap_or(a)`
                               //~| NOTE replace `map(|x| x + 1).unwrap_or(0)`
               .unwrap_or(0); // should lint even though this call is on a separate line
    // multi line cases
    let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)`
                        x + 1
                    }
              ).unwrap_or(0);
    let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)`
               .unwrap_or({
                    0
                });
    // macro case
    let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint

    // Check OPTION_MAP_UNWRAP_OR_ELSE
    // single line case
    let _ = opt.map(|x| x + 1) //~  ERROR called `map(f).unwrap_or_else(g)`
                               //~| NOTE replace `map(|x| x + 1).unwrap_or_else(|| 0)`
               .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
    // multi line cases
    let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or_else(g)`
                        x + 1
                    }
              ).unwrap_or_else(|| 0);
    let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)`
               .unwrap_or_else(||
                    0
                );
    // macro case
    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint

}

/// Struct to generate false positive for Iterator-based lints
#[derive(Copy, Clone)]
struct IteratorFalsePositives {
    foo: u32,
}

impl IteratorFalsePositives {
    fn filter(self) -> IteratorFalsePositives {
        self
    }

    fn next(self) -> IteratorFalsePositives {
        self
    }

    fn find(self) -> Option<u32> {
        Some(self.foo)
    }

    fn position(self) -> Option<u32> {
        Some(self.foo)
    }

    fn rposition(self) -> Option<u32> {
        Some(self.foo)
    }
}

/// Checks implementation of FILTER_NEXT lint
fn filter_next() {
    let v = vec![3, 2, 1, 0, -1, -2, -3];

    // check single-line case
    let _ = v.iter().filter(|&x| *x < 0).next();
    //~^ ERROR called `filter(p).next()` on an Iterator.
    //~| NOTE replace `filter(|&x| *x < 0).next()`

    // check multi-line case
    let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator.
                                *x < 0
                            }
                   ).next();

    // check that we don't lint if the caller is not an Iterator
    let foo = IteratorFalsePositives { foo: 0 };
    let _ = foo.filter().next();
}

/// Checks implementation of SEARCH_IS_SOME lint
fn search_is_some() {
    let v = vec![3, 2, 1, 0, -1, -2, -3];

    // check `find().is_some()`, single-line
    let _ = v.iter().find(|&x| *x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `find(|&x| *x < 0).is_some()`

    // check `find().is_some()`, multi-line
    let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching
                              *x < 0
                          }
                   ).is_some();

    // check `position().is_some()`, single-line
    let _ = v.iter().position(|&x| x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `position(|&x| x < 0).is_some()`

    // check `position().is_some()`, multi-line
    let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching
                                  x < 0
                              }
                   ).is_some();

    // check `rposition().is_some()`, single-line
    let _ = v.iter().rposition(|&x| x < 0).is_some();
    //~^ ERROR called `is_some()` after searching
    //~| NOTE replace `rposition(|&x| x < 0).is_some()`

    // check `rposition().is_some()`, multi-line
    let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching
                                   x < 0
                               }
                   ).is_some();

    // check that we don't lint if the caller is not an Iterator
    let foo = IteratorFalsePositives { foo: 0 };
    let _ = foo.find().is_some();
    let _ = foo.position().is_some();
    let _ = foo.rposition().is_some();
}

/// Checks implementation of the OR_FUN_CALL lint
fn or_fun_call() {
    struct Foo;

    impl Foo {
        fn new() -> Foo { Foo }
    }

    fn make<T>() -> T { unimplemented!(); }

    let with_constructor = Some(vec![1]);
    with_constructor.unwrap_or(make());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_constructor.unwrap_or_else(make)

    let with_new = Some(vec![1]);
    with_new.unwrap_or(Vec::new());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_new.unwrap_or_default();

    let with_const_args = Some(vec![1]);
    with_const_args.unwrap_or(Vec::with_capacity(12));
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_const_args.unwrap_or_else(|| Vec::with_capacity(12));

    let with_err : Result<_, ()> = Ok(vec![1]);
    with_err.unwrap_or(make());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_err.unwrap_or_else(|_| make());

    let with_err_args : Result<_, ()> = Ok(vec![1]);
    with_err_args.unwrap_or(Vec::with_capacity(12));
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_err_args.unwrap_or_else(|_| Vec::with_capacity(12));

    let with_default_trait = Some(1);
    with_default_trait.unwrap_or(Default::default());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_default_trait.unwrap_or_default();

    let with_default_type = Some(1);
    with_default_type.unwrap_or(u64::default());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_default_type.unwrap_or_default();

    let with_vec = Some(vec![1]);
    with_vec.unwrap_or(vec![]);
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);

    let without_default = Some(Foo);
    without_default.unwrap_or(Foo::new());
    //~^ERROR use of `unwrap_or`
    //~|HELP try this
    //~|SUGGESTION without_default.unwrap_or_else(Foo::new);

    let mut map = HashMap::<u64, String>::new();
    map.entry(42).or_insert(String::new());
    //~^ERROR use of `or_insert` followed by a function call
    //~|HELP try this
    //~|SUGGESTION map.entry(42).or_insert_with(String::new);

    let mut btree = BTreeMap::<u64, String>::new();
    btree.entry(42).or_insert(String::new());
    //~^ERROR use of `or_insert` followed by a function call
    //~|HELP try this
    //~|SUGGESTION btree.entry(42).or_insert_with(String::new);
}

fn main() {
    use std::io;

    let opt = Some(0);
    let _ = opt.unwrap();  //~ERROR used unwrap() on an Option

    let res: Result<i32, ()> = Ok(0);
    let _ = res.unwrap();  //~ERROR used unwrap() on a Result

    let _ = "str".to_string();  //~ERROR `"str".to_owned()` is faster

    let v = &"str";
    let string = v.to_string();  //~ERROR `(*v).to_owned()` is faster
    let _again = string.to_string();  //~ERROR `String::to_string` is an inefficient way to clone a `String`; use `clone()` instead

    res.ok().expect("disaster!"); //~ERROR called `ok().expect()`
    // the following should not warn, since `expect` isn't implemented unless
    // the error type implements `Debug`
    let res2: Result<i32, MyError> = Ok(0);
    res2.ok().expect("oh noes!");
    // we currently don't warn if the error type has a type parameter
    // (but it would be nice if we did)
    let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0);
    res3.ok().expect("whoof");
    let res4: Result<u32, io::Error> = Ok(0);
    res4.ok().expect("argh"); //~ERROR called `ok().expect()`
    let res5: io::Result<u32> = Ok(0);
    res5.ok().expect("oops"); //~ERROR called `ok().expect()`
    let res6: Result<u32, &str> = Ok(0);
    res6.ok().expect("meh"); //~ERROR called `ok().expect()`
}

struct MyError(()); // doesn't implement Debug

#[derive(Debug)]
struct MyErrorWithParam<T> {
    x: T
}

fn starts_with() {
    "".chars().next() == Some(' ');
    //~^ ERROR starts_with
    //~| HELP like this
    //~| SUGGESTION "".starts_with(' ')

    Some(' ') != "".chars().next();
    //~^ ERROR starts_with
    //~| HELP like this
    //~| SUGGESTION !"".starts_with(' ')
}

fn use_extend_from_slice() {
    let mut v : Vec<&'static str> = vec![];
    v.extend(&["Hello", "World"]); //~ERROR use of `extend`
    v.extend(&vec!["Some", "more"]);
    //~^ERROR use of `extend`
    //~| HELP try this
    //~| SUGGESTION v.extend_from_slice(&vec!["Some", "more"]);

    v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend`
    let o : Option<&'static str> = None;
    v.extend(o);
    v.extend(Some("Bye"));
    v.extend(vec!["Not", "like", "this"]);
    v.extend(["But", "this"].iter());
    //~^ERROR use of `extend
    //~| HELP try this
    //~| SUGGESTION v.extend_from_slice(&["But", "this"]);
}

fn clone_on_copy() {
    42.clone(); //~ERROR using `clone` on a `Copy` type
    vec![1].clone(); // ok, not a Copy type
    Some(vec![1]).clone(); // ok, not a Copy type
}

fn clone_on_copy_generic<T: Copy>(t: T) {
    t.clone(); //~ERROR using `clone` on a `Copy` type
    Some(t).clone(); //~ERROR using `clone` on a `Copy` type
}

fn clone_on_double_ref() {
    let x = vec![1];
    let y = &&x;
    let z: &Vec<_> = y.clone(); //~ERROR using `clone` on a double
                                //~| HELP try dereferencing it
                                //~| SUGGESTION let z: &Vec<_> = (*y).clone();
                                //~^^^ERROR using `clone` on a `Copy` type
    println!("{:p} {:p}",*y, z);
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;

use std::thread;
use std::env;
use std::io::stdout;
use sozu_command::logging::{Logger,LoggerBackend};
use sozu_command::proxy;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::channel::Channel;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()), None);
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()), None);
  }

  info!("MAIN\tstarting up");

  sozu::metrics::setup(&"127.0.0.1:8125".parse().unwrap(), "main", false, None);
  gauge!("sozu.TEST", 42);

  let config = proxy::HttpListener {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    sozu::http::start(config, channel, max_buffers, buffer_size);
  });

  let http_front = proxy::HttpFront {
    app_id:     String::from("app_1"),
    address:    "127.0.0.1:8080".parse().unwrap(),
    hostname:   String::from("lolcatho.st"),
    path_begin: String::from("/")
  };

  let http_backend = proxy::Backend {
    app_id:      String::from("app_1"),
    backend_id:  String::from("app_1-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_ABCD"),
    order: proxy::ProxyRequestData::AddHttpFront(http_front)
  });

  command.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_EFGH"),
    order: proxy::ProxyRequestData::AddBackend(http_backend)
  });

  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = proxy::HttpsListener {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    sozu::https_rustls::configuration::start(config, channel2, max_buffers, buffer_size);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = proxy::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec!()
  };
  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_IJKL1"),
    order: proxy::ProxyRequestData::AddCertificate(proxy::AddCertificate{
      front: "127.0.0.1:8443".parse().unwrap(),
      certificate: certificate_and_key,
      names: Vec::new(),
    })
  });

  let tls_front = proxy::HttpFront {
    app_id:      String::from("app_1"),
    address:     "127.0.0.1:8443".parse().unwrap(),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_IJKL2"),
    order: proxy::ProxyRequestData::AddHttpsFront(tls_front)
  });
  let tls_backend = proxy::Backend {
    app_id:      String::from("app_1"),
    backend_id:  String::from("app_1-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_MNOP"),
    order: proxy::ProxyRequestData::AddBackend(tls_backend)
  });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = proxy::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec!()
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_QRST1"),
    order: proxy::ProxyRequestData::AddCertificate(proxy::AddCertificate {
      front: "127.0.0.1:8443".parse().unwrap(),
      certificate: certificate_and_key2,
      names: Vec::new(),
    })
  });

  let tls_front2 = proxy::HttpFront {
    app_id:      String::from("app_2"),
    address:     "127.0.0.1:8443".parse().unwrap(),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_QRST2"),
    order: proxy::ProxyRequestData::AddHttpsFront(tls_front2)
  });

  let tls_backend2 = proxy::Backend {
    app_id:      String::from("app_2"),
    backend_id:  String::from("app_2-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_UVWX"),
    order: proxy::ProxyRequestData::AddBackend(tls_backend2)
  });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<commit_msg>fix example compilation<commit_after>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;

use std::thread;
use std::env;
use std::io::stdout;
use sozu_command::logging::{Logger,LoggerBackend};
use sozu_command::proxy;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::channel::Channel;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()), None);
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()), None);
  }

  info!("MAIN\tstarting up");

  sozu::metrics::setup(&"127.0.0.1:8125".parse().unwrap(), "main", false, None);
  gauge!("sozu.TEST", 42);

  let config = proxy::HttpListener {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    sozu::http::start(config, channel, max_buffers, buffer_size);
  });

  let http_front = proxy::HttpFront {
    app_id:     String::from("app_1"),
    address:    "127.0.0.1:8080".parse().unwrap(),
    hostname:   String::from("lolcatho.st"),
    path_begin: String::from("/")
  };

  let http_backend = proxy::Backend {
    app_id:      String::from("app_1"),
    backend_id:  String::from("app_1-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_ABCD"),
    order: proxy::ProxyRequestData::AddHttpFront(http_front)
  });

  command.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_EFGH"),
    order: proxy::ProxyRequestData::AddBackend(http_backend)
  });

  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = proxy::HttpsListener {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    let max_buffers = 500;
    let buffer_size = 16384;
    sozu::https_rustls::configuration::start(config, channel2, max_buffers, buffer_size);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = proxy::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec![],
    versions:          vec![],
  };
  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_IJKL1"),
    order: proxy::ProxyRequestData::AddCertificate(proxy::AddCertificate{
      front: "127.0.0.1:8443".parse().unwrap(),
      certificate: certificate_and_key,
      names: Vec::new(),
    })
  });

  let tls_front = proxy::HttpFront {
    app_id:      String::from("app_1"),
    address:     "127.0.0.1:8443".parse().unwrap(),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_IJKL2"),
    order: proxy::ProxyRequestData::AddHttpsFront(tls_front)
  });
  let tls_backend = proxy::Backend {
    app_id:      String::from("app_1"),
    backend_id:  String::from("app_1-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_MNOP"),
    order: proxy::ProxyRequestData::AddBackend(tls_backend)
  });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = proxy::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec![],
    versions:          vec![],
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_QRST1"),
    order: proxy::ProxyRequestData::AddCertificate(proxy::AddCertificate {
      front: "127.0.0.1:8443".parse().unwrap(),
      certificate: certificate_and_key2,
      names: Vec::new(),
    })
  });

  let tls_front2 = proxy::HttpFront {
    app_id:      String::from("app_2"),
    address:     "127.0.0.1:8443".parse().unwrap(),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_QRST2"),
    order: proxy::ProxyRequestData::AddHttpsFront(tls_front2)
  });

  let tls_backend2 = proxy::Backend {
    app_id:      String::from("app_2"),
    backend_id:  String::from("app_2-0"),
    sticky_id:   None,
    address:     "127.0.0.1:1026".parse().unwrap(),
    load_balancing_parameters: Some(LoadBalancingParams::default()),
    backup:      None,
  };

  command2.write_message(&proxy::ProxyRequest {
    id:    String::from("ID_UVWX"),
    order: proxy::ProxyRequestData::AddBackend(tls_backend2)
  });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<|endoftext|>